-- PressFontWidths.mesa, edit by Johnsson; July 9, 1980  2:09 PM
-- converted to Laurel by Ken Pier, July 30, 1981  9:17 AM 
-- fixed INTEGER[p] in ScaleThings, August 5, 1981  11:11 AM 
-- added FreeCacheEntry, August 10, 1981  5:10 PM 
-- converted to Laurel 6.1 by Ken Pier, May 17, 1983  10:39 AM

DIRECTORY
  InlineDefs USING [LongDiv, LongMult],
  Press USING [
    FontSlope, FontWeight, magicNonPrintingWidth, Mica,
    micasPerInch, Points, pointsPerInch],
  PressUtilities USING [],
  intCommon USING [user],
  PrintDefs USING[PError, DestroyS],
  Core: FROM "Core" USING [--FreeCacheEntry,--Login ],
  csD: FROM "CoreStreamDefs";

PressFontWidths: PROGRAM
  IMPORTS intCommon, PrintDefs, InlineDefs, csD, Core
  EXPORTS PressUtilities =
  BEGIN
  
  FontSlope: TYPE = Press.FontSlope;
  FontWeight: TYPE = Press.FontWeight;
  Mica: TYPE = Press.Mica;
  Points: TYPE = Press.Points;
  
  -- bug in us, or file in wrong format
  
  FontName: TYPE = PACKED ARRAY [0..20) OF BYTE;
  FontFace: TYPE = [0..2*3*3); -- this wasn't my idea
  
  BYTE: TYPE = [0..377B];
  
  -- see [MAXC]<Press>FontFormats.bravo
  -- if index.size=0, then numbers need to be scaled by points*2540/72000
  
  IX: TYPE = MACHINE DEPENDENT RECORD [type: [0..17B), length: [0..7777B]];
  IXN: TYPE = MACHINE DEPENDENT RECORD [e: IX, code: WORD, name: FontName];
  SDTIX: TYPE = MACHINE DEPENDENT RECORD [
    e: IX,
    code, face: BYTE,
    bc, ec: CHARACTER,
    size: Points,
    rotation: INTEGER,
    x1, location, x2, length: CARDINAL]; -- position in file
  
  WidthSegment: TYPE = MACHINE DEPENDENT RECORD [
    fBBox, fBBoy, fBBdx, fBBdy: WORD, xFeed, yFeed: BOOLEAN, xxx: [0..37777B]];
  
  ComputeFontFace: PROCEDURE [w: FontWeight, s: FontSlope]
    RETURNS [ff: FontFace] =
    BEGIN
    ff ← 0;
    SELECT w FROM
      medium => ff ← ff + 0;
      bold => ff ← ff + 2;
      --light => ff ← ff+4;
      
      ENDCASE => PrintDefs.PError[BadParameters];
    SELECT s FROM
      regular => ff ← ff + 0;
      italic => ff ← ff + 1;
      ENDCASE => PrintDefs.PError[BadParameters];
    --SELECT expansion FROM
    --  regular => ff ← ff+0;
    --  condensed => ff ← ff+6;
    --  expanded => ff ← ff+12;
    --  ENDCASE => PrintDefs.PError[BadParameters];
    
    END;
    
  FindFontWidths: PUBLIC PROCEDURE [
    family: STRING, points: Points, weight: FontWeight, slope: FontSlope,
    widths: POINTER TO ARRAY CHARACTER OF Mica]
    RETURNS [fBBox, fBBoy, fBBdx, fBBdy: Mica] =
    BEGIN
    
    ScaleThings: PROCEDURE [p: CARDINAL] RETURNS [Mica] =
      BEGIN OPEN InlineDefs;
      pp: INTEGER ← LOOPHOLE[p];
      IF pp = Press.magicNonPrintingWidth THEN RETURN[pp];
      IF index.size # 0 THEN RETURN[pp];
      -- This will overflow at about 200 points.
      IF p IN [0..77777B] THEN RETURN[LongDiv[LongMult[254*points, pp], 7200]];
      RETURN[-LongDiv[LongMult[254*points, -pp], 7200]];
      END;
      
    ff: FontFace = ComputeFontFace[weight, slope];
    i: CARDINAL;
    c: CHARACTER;
    code: WORD;
    nameFound, indexFound: BOOLEAN ← FALSE;
    pointSizeInMicas: Mica;
    name: FontName;
    e: IX;
    header: IXN;
    index: SDTIX;
    width: WidthSegment;
    x: WORD;

    s: csD.StreamHandle ← NIL;

    BEGIN ENABLE UNWIND => {s ← PrintDefs.DestroyS[s];};

    Core.Login[@intCommon.user];
    s ← csD.OpenFromName["Fonts.widths"L, word, read];
    --Core.FreeCacheEntry["Fonts.widths"L];--
    BEGIN OPEN InlineDefs; -- else overflows at about 25 points
    pointSizeInMicas ← LongDiv[
      LongMult[Press.micasPerInch, points], Press.pointsPerInch];
    END;

    -- copy over the family name into Fonts.Widths format
    IF family.length~ IN (0..19] THEN PrintDefs.PError[BadParameters];
    FOR i IN [0..20) DO name[i] ← 0; ENDLOOP;
    name[0] ← family.length;
    FOR i IN [0..family.length) DO
      SELECT family[i] FROM
	IN ['A..'Z] => name[i + 1] ← LOOPHOLE[family[i]];
	IN ['a..'z] => name[i + 1] ← LOOPHOLE[family[i], BYTE] - 40B;
	ENDCASE => PrintDefs.PError[BadParameters];
      ENDLOOP;
    DO
      IF csD.ReadBlock[s, @e, 0, SIZE[IX]] = 0
					THEN PrintDefs.PError[ErrorReadingFontWidths];
      SELECT e.type FROM
	0 => EXIT;
	1 =>
	  BEGIN
	  IF e.length # SIZE[IXN] THEN PrintDefs.PError[ErrorReadingFontWidths];
	  IF csD.ReadBlock[s, @header + 1, 0, SIZE[IXN] - 1] = 0 THEN
	    PrintDefs.PError[ErrorReadingFontWidths];
	  IF EqualName[@name, @header.name] THEN
	    BEGIN code ← header.code; nameFound ← TRUE; END;
	  END;
	4 =>
	  BEGIN
	  IF e.length # SIZE[SDTIX] THEN PrintDefs.PError[ErrorReadingFontWidths];
	  IF csD.ReadBlock[s, @index + 1, 0, SIZE[SDTIX] - 1] = 0 THEN
	    PrintDefs.PError[ErrorReadingFontWidths];
	  IF nameFound AND code = index.code AND ff = index.face AND
	   index.rotation = 0 AND (index.size = 0 OR INTEGER[index.size] =
	    pointSizeInMicas) THEN BEGIN indexFound ← TRUE; EXIT; END;
	  END;
	ENDCASE => PrintDefs.PError[ErrorReadingFontWidths];
      ENDLOOP;
    IF ~indexFound THEN PrintDefs.PError[FontNotInFontsDotWidths];
    IF index.x1 # 0 OR index.x2 # 0 THEN
								PrintDefs.PError[ErrorReadingFontWidths];
    -- position file to starting byte of our info
    csD.SetPosition[s, index.location];
    IF csD.ReadBlock[s, @width, 0, SIZE[WidthSegment]] = 0 THEN
      PrintDefs.PError[ErrorReadingFontWidths];
    fBBox ← ScaleThings[width.fBBox];
    fBBoy ← ScaleThings[width.fBBoy];
    fBBdx ← ScaleThings[width.fBBdx];
    fBBdy ← ScaleThings[width.fBBdy];
    IF width.xFeed THEN
      BEGIN
      x ← ScaleThings[csD.Read[s]];
      FOR c IN [index.bc..index.ec] DO widths[c] ← x; ENDLOOP;
      END
    ELSE
      BEGIN
      FOR c IN [index.bc..index.ec] DO widths[c] ← ScaleThings[csD.Read[s]]; ENDLOOP;
      END;
    s ← PrintDefs.DestroyS[s];
    END;-- of ENABLED BEGIN
    END;-- of PROC FindFontWidths
    
  EqualName: PROCEDURE [n1, n2: POINTER TO FontName] RETURNS [BOOLEAN] =
    BEGIN
    i: CARDINAL;
    FOR i IN [0..20) DO IF n1[i] # n2[i] THEN RETURN[FALSE]; ENDLOOP;
    RETURN[TRUE];
    END;
    
  
  END.

--Former Errors
  FontNotInFontsDotWidths: PUBLIC ERROR = CODE;
  ErrorReadingFontWidths: PUBLIC ERROR = CODE;