<> <> <> DIRECTORY TSTypes, TSFontTable, Rope, TSFont, TSGlue; TSFontImpl: CEDAR MONITOR IMPORTS TSTypes, TSFontTable, Rope EXPORTS TSFont = BEGIN OPEN TSTypes, TSFont; FontNotFound: PUBLIC SIGNAL [name: Rope.ROPE] RETURNS [substituteName: Rope.ROPE] = CODE; TooManyFonts: PUBLIC SIGNAL = CODE; Byte: TYPE = [0..256); tableSize: NAT = 209; table: ARRAY [0..tableSize) OF LIST OF Ref; -- in buckets by name Reset: PUBLIC ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; FOR f:[0..tableSize) IN [0..tableSize) DO table[f] _ NIL ENDLOOP END; Lookup: PUBLIC ENTRY PROCEDURE[ name:Rope.ROPE, size:Dimn _ nilDimn, rotation: INTEGER _ 0] RETURNS [Ref] = BEGIN ENABLE UNWIND => NULL; f: [0..tableSize); r: LIST OF Ref; fontTable:TSFontTable.Ref _ NIL; WHILE fontTable = NIL DO f _ Find[name]; IF table[f] = NIL THEN fontTable _ TSFontTable.Load[name] ELSE fontTable _ table[f].first.fontTable; IF fontTable = NIL THEN name _ SIGNAL FontNotFound[name]; ENDLOOP; IF size = nilDimn THEN size _ fontTable.headerInfo.designSize; r _ table[f]; WHILE r # NIL AND (r.first.size # size OR r.first.rotation # rotation) DO r _ r.rest; ENDLOOP; IF r = NIL THEN BEGIN t: Ref _ NEW[FontRec]; t.size _ size; t.rotation _ rotation; t.spaceGlue.space _ RealDimn[fontTable.parameters[spaceWidth], size]; t.spaceGlue.stretch _ RealDimn[fontTable.parameters[spaceStretch], size]; t.spaceGlue.shrink _ RealDimn[fontTable.parameters[spaceShrink], size]; t.bc _ fontTable.bc; t.ec _ fontTable.ec; t.metrics _ NEW[MetricSequenceRec[t.ec-t.bc+1]]; FOR i: NAT IN [0..t.ec-t.bc] DO OPEN fontTable^; info: TSFontTable.FInfoEntry _ fInfoTable[LOOPHOLE[t.bc,Byte]+i]; t.metrics[i].width _ RealDimn[widthTable[info.widthIndex], size]; t.metrics[i].height _ RealDimn[heightTable[info.heightIndex], size]; t.metrics[i].depth _ RealDimn[depthTable[info.depthIndex], size]; ENDLOOP; t.fontTable _ fontTable; table[f] _ r _ CONS[t,table[f]]; END; RETURN[r.first]; END; totalFinds, totalProbes: LONG INTEGER _ 0; -- some statistics Find: PROCEDURE [name: Rope.ROPE] RETURNS [f:[0..tableSize)] = BEGIN probes: NAT _ 0; f _ Hash[name]; THROUGH [0..tableSize] UNTIL table[f]=NIL OR Rope.Equal[table[f].first.fontTable.name,name,FALSE] DO IF f=0 THEN f_tableSize-1 ELSE f _ f-1; probes _ probes+1; ENDLOOP; IF probes > tableSize THEN ERROR TooManyFonts; totalFinds _ totalFinds+1; totalProbes _ totalProbes + probes; END; Hash: PROCEDURE [name: Rope.ROPE] RETURNS [[0..tableSize)] = BEGIN g: NAT _ 0; HashChar: SAFE PROC [c: CHAR] RETURNS [BOOLEAN _ FALSE] = { g _ 5*g + LOOPHOLE[c,[0..256)]; IF g > (LAST[NAT]-255)/5 THEN g _ g MOD tableSize }; [] _ Rope.Map[base: name, action: HashChar]; RETURN[g MOD tableSize] END; ParcFontSpecification: PUBLIC PROCEDURE [f:Ref] RETURNS [family: Rope.ROPE, micaSize: NAT, face: [0..255], rotation: INTEGER] = BEGIN OPEN f.fontTable^; family _ headerInfo.family; face _ headerInfo.face; micaSize _ DimnInt[f.size,mica]; rotation _ f.rotation; END; CharDimensions: PUBLIC PROCEDURE [r: Ref, c: CHAR] RETURNS [extent: Dimensions] = BEGIN IF c IN [r.bc..r.ec] THEN { m: MetricRec _ r.metrics[c - r.bc]; extent[right] _ m.width; extent[left] _ zeroDimn; extent[up] _ m.height; extent[down] _ m.depth; } ELSE extent _ [zeroDimn, zeroDimn, zeroDimn, zeroDimn]; END; Width: PUBLIC PROCEDURE [r: Ref, c: CHAR] RETURNS [TSTypes.Dimn] = {RETURN[IF c IN [r.bc..r.ec] THEN r.metrics[c - r.bc].width ELSE zeroDimn]}; CharItalicCorr: PUBLIC PROCEDURE [r: Ref, c: CHAR] RETURNS [TSTypes.Dimn] = BEGIN OPEN r.fontTable^; IF c IN [bc..ec] THEN { info: TSFontTable.FInfoEntry _ fInfoTable[LOOPHOLE[c,Byte]]; RETURN[RealDimn[charIcTable[info.charIcIndex], r.size]]; } ELSE RETURN[zeroDimn]; END; SpaceGlue: PUBLIC PROCEDURE [r: Ref] RETURNS [g: TSGlue.Glue] = {g _ r.spaceGlue}; END. Michael Plass, September 7, 1982 3:55 pm. Reworked metric fetching to avoid rescaling. Michael Plass, September 15, 1982 9:36 am. ENABLE UNWIND => NULL. Michael Plass, November 2, 1982 10:17 am. CEDARized.