-- TexGlue.Mesa

-- implementation of procedures in TexGlueDefs
-- last written by Doug Wyatt, December 5, 1979  6:30 PM

DIRECTORY
	TexDefs: FROM "TexDefs",
	TexGlueDefs: FROM "TexGlueDefs",
	TexMemDefs: FROM "TexMemDefs",
	InlineDefs: FROM "InlineDefs";

TexGlue: PROGRAM
IMPORTS TexMemDefs, InlineDefs
EXPORTS TexGlueDefs =
BEGIN OPEN TexDefs, TexGlueDefs;

-- eventually, some of these procedures should be made INLINE
-- and moved to TexGlueDefs

ClearFlexSums: PUBLIC PROCEDURE[sums: FlexSumsPtr] =
	BEGIN
	sums↑←[[0,0,0],[0,0,0]];
	END;

SumFlex: PUBLIC PROCEDURE[glue: GluePtr, sums: FlexSumsPtr] =
	BEGIN
	dir: FlexDir;
	vec: FlexVecPtr;
	flex: Flex;
	FOR dir IN FlexDir
		DO
		vec←@sums[dir];
		flex←glue.flex[dir];
		vec[flex.order]←vec[flex.order]+flex.val;
		ENDLOOP;
	END;

DominantFlex: PUBLIC PROCEDURE[vec: FlexVecPtr] RETURNS[Flex] =
	BEGIN
	ord: FlexOrder;
	FOR ord DECREASING IN FlexOrder
		DO
		IF vec[ord]#0 THEN RETURN[[order: ord, val: vec[ord]]];
		ENDLOOP;
	RETURN[zeroFlex];
	END;

nullGlueSpec: GlueSpec = [refs: 0, space: 0, flex: [zeroFlex,zeroFlex]];

MakeGlue: PUBLIC PROCEDURE RETURNS[GluePtr] =
	BEGIN
	p: GluePtr←TexMemDefs.AllocMem[SIZE[GlueSpec]];
	p↑←nullGlueSpec;
	RETURN[p];
	END;

AddGlueLink: PUBLIC PROCEDURE[p: GluePtr] =
	BEGIN
	IF p.refs#infRefs THEN p.refs←p.refs+1;
	END;

DelGlueLink: PUBLIC PROCEDURE[p: GluePtr] =
	BEGIN
	SELECT p.refs FROM
		1 => TexMemDefs.FreeMem[p,SIZE[GlueSpec]]; -- deallocate if only 1 ref
		infRefs => NULL; -- glue with infinite ref count is permanent
		ENDCASE => p.refs←p.refs-1; -- just decrement ref count
	END;

CommonGlueArray: TYPE = ARRAY CommonGlueType OF GlueSpec;
commonGlue: POINTER TO CommonGlueArray←NIL;

GlueInit: PROCEDURE =
	BEGIN
	g: CommonGlueType;
	p: GluePtr;
	fillFlex: Flex=[fill,1];
	lowerfillFlex: Flex=[lowerfill,1];
	filFlex: Flex=lowerfillFlex;
	filnegFlex: Flex=[filFlex.order,-filFlex.val];
	commonGlue←TexMemDefs.AllocMem[SIZE[CommonGlueArray]];
	FOR g IN CommonGlueType
		DO p←@commonGlue[g]; p.refs←infRefs; p.space←0 ENDLOOP;
	commonGlue[zero].flex←[zeroFlex,zeroFlex];
	commonGlue[fill].flex←[fillFlex,zeroFlex];
	commonGlue[fil].flex←[filFlex,zeroFlex];
	commonGlue[filneg].flex←[filnegFlex,zeroFlex];
	commonGlue[lowerfill].flex←[lowerfillFlex,lowerfillFlex];
	END;

CommonGlue: PUBLIC PROCEDURE[g: CommonGlueType] RETURNS[GluePtr] =
	BEGIN RETURN[@commonGlue[g]] END;


Overfull: PUBLIC SIGNAL[excess: Dimn] = CODE;

SetGlue: PUBLIC PROCEDURE[dir: FlexDir, delta: Dimn, sums: FlexSumsPtr]
	RETURNS[GlueSet] =
	BEGIN
	flex: Flex←DominantFlex[@sums[dir]];
	v: FlexVal←flex.val;
	fuzz: Dimn=4; -- about a tenth of a point
	IF dir=shr AND flex.order=regular AND delta>v+fuzz THEN
		BEGIN -- overfull box
		SIGNAL Overfull[delta-v];
		v←delta; -- so num/den=1
		END;
	IF v=0 THEN RETURN[zeroGlueSet]
	ELSE RETURN[[dir: dir, order: flex.order, num: delta, den: v]];
	END;

FixGlue: PUBLIC PROCEDURE[glue: GluePtr, set: GlueSet] RETURNS[Dimn] =
	BEGIN
	s: Dimn←glue.space;
	flex: Flex←glue.flex[set.dir];
	IF flex.order=set.order --AND set.num#0-- THEN
		BEGIN --	s←s+(set.num*flex.val)/set.den;
		v: FlexVal;
		t: LONG INTEGER;
		v←flex.val; IF set.dir=shr THEN v←-v;
		t←v; t←(t*set.num)/set.den;
		s←s+InlineDefs.LowHalf[t];
		-- *** worry about rounding and overflow? ***
		END;
	RETURN[s];
	END;


GluePenalty: PUBLIC PROCEDURE[set: GlueSet] RETURNS[Penalty] =
	BEGIN OPEN set;
	t: LONG INTEGER;
	-- no penalty for stretching/shrinking fill glue
	IF order#regular THEN RETURN[0];
	-- can't do anything if not flex
	-- and can't shrink more than shrinkability
	IF (dir=shr AND num>den) OR den<=0 THEN RETURN[maxPenalty];
	-- for regular glue, penalty is 100*(num/den)↑3
	t←1000; THROUGH [1..3] DO
		IF t>maxPenalty THEN t←maxPenalty;
		t←(t*num)/den;
		ENDLOOP;
	t←(t+5)/10;
	IF t>maxPenalty THEN t←maxPenalty;
	RETURN[InlineDefs.LowHalf[t]];
	END;


-- initialization

GlueInit;

END.