{File name:  LineBreak.mc
Description: LineBreak opcode
Author: JPM
Created: December 17, 1986
Last Edited:
JPM	December 31, 1986	Fix bug in LBReadPriorIndex (wrong offset)
JPM	December 30, 1986	Add (and use) suffixHardHyphen; fix bug in LBTextCross (can't use r0100)
JPM	December 19, 1986	Revise algorithm per LineBreakImpl.mesa}

{ 	Copyright (C) 1986 by Xerox Corporation.  All rights reserved.}

{Link register use:
	L0 - returns from MapSrc and MapDst subroutines
	L1 - need to write prior U-regs into arg (1 = FALSE, 0 = TRUE) -- init after calls to MapSrc/MapDst
	L2 - hyphenate flag (2 = FALSE, 3 = TRUE)
	L3 - misc. flow control
	L4 - word.notPunctuation flag (2 = FALSE, 3 = TRUE)}

{return reasons}
Set[reasonMargin, 0];
Set[reasonNormal, 1];
Set[reasonChangeBase, 2];
Set[reasonInvalidCache, 3];
Set[reasonContiguousWords, 4];
Set[reasonUnableToBreak, 5];
Set[reasonSpecialGermanCase, 6];

{escape types}
Set[escapeSpace, Or[Lshift[0,1],9]];
Set[escapeZeroWidthSpace, Or[Lshift[1,1],9]];
Set[escapeChangeBase, Or[Lshift[2,1],9]];

{state field constants}
Set[spaceCountIncr, Lshift[1,4]];
Set[notPunctuationTRUE, Lshift[1,3]];
Set[suffixCharField, 7];

{suffixChar types}
Set[suffixSpace, 0];
Set[suffixZeroWidthSpace, 1];
Set[suffixHyphen, 2];
Set[suffixHardHyphen, 3];
Set[suffixNull, 4];

@LINEBREAK:
	rhVirtualH ← TOS LRot0,						c1, at[0E,10,ESCAn];
	rVirtualL ← STK, pop, L0 ← L0.LineBreak,			c2;
	rVirtualL ← rVirtualL + 2, fXpop, push, CALL[MapDst],		c3; {get length 1st}

{MapDst subroutine starts in c1, ends in c2}
	rCtMinusIx ← MD {text.LENGTH},					c3, MapDstRet[L0.LineBreak];

	MAR ← [rhArgReal, rArgReal + 9],				c1; {offset 0B - 2}
	uLBTextCount ← rCtMinusIx, CANCELBR[$,2],			c2;
	Q ← MD {final.index},						c3;

	MAR ← rArgReal ← [rhArgReal, rArgReal - 2],			c1; {start of arg}
	rCtMinusIx ← rCtMinusIx - Q, ZeroBr, CANCELBR[$,2],		c2;
	uLBArgRealLo ← rArgReal, rVirtualL ← MD {text lo}, BRANCH[$,LBFastExit], c3;

	MAR ← [rhArgReal, rArgReal + 1], L3 ← 0,			c1;
	rVirtualL ← rVirtualL + Q, CarryBr, CANCELBR[$,2],		c2;
	uLBTextRealLo ← rVirtualL, rhVirtualH ← MD {text hi}, BRANCH[$,LBUpdateHigh], c3;

	MAR ← [rhArgReal, rArgReal + 0E],				c1, at[0,10,LBUpdateHighRet];
	Q ← ~suffixCharField, CANCELBR[$,2],				c2;
	rhSuffixChar ← MD {final.suffixChar}, rSpCount ← MD and Q {final.count/notPunctuation}, c3;

	MAR ← [rhArgReal, rArgReal + 0D],				c1;
	Q ← rhSuffixChar xor rSpCount, CANCELBR[$,2],			c2;
	rBitLength ← MD {final.bitLength},				c3;

	MAR ← [rhArgReal, rArgReal + 3],				c1;
	rhSuffixChar ← Q LRot0, CANCELBR[$,2],				c2;
	Q ← MD {cache lo},						c3;

	MAR ← [rhArgReal, rArgReal + 4],				c1;
	uLBCacheLo ← Q, CANCELBR[$,2],					c2;
	Q ← MD {cache hi},						c3;

	MAR ← [rhArgReal, rArgReal + 5],				c1;
	uLBCacheHi ← Q, CANCELBR[$,2],					c2;
	Q ← MD {hyphenate/font}, XHDisp,				c3;

	MAR ← [rhArgReal, rArgReal + 6], L2 ← 2, BRANCH[$,LBSetHyphenate,2], c1;
	CANCELBR[LBInitCont,2],						c2;
LBSetHyphenate:
	Q ← Q and ~u8000, CANCELBR[$,2],				c2; {clear high bit}
LBInitCont:
	rMargin ← MD {margin},						c3;

	MAR ← [rhArgReal, rArgReal + 7],				c1;
	uLBFont ← Q, CANCELBR[$,2],					c2;
	UrG ← G, rMinSpPLength ← MD {hyphenPixelLength/minSpacePixelLength}, c3;

	MAR ← [rhArgReal, rArgReal + 9],				c1;
	rhLBHyphenPL ← rMinSpPLength LRot8, CANCELBR[$,2],		c2;
	UrL ← L, rMinSpMLength ← MD {minSpaceMicaLength},		c3;

	MAR ← [rhArgReal, rArgReal + 0A],				c1;
	rMinSpPLength ← rMinSpPLength and 0FF, CANCELBR[$,2],		c2;
	UrPC ← PC, rWhiteSpaceIncr ← MD {whiteSpace},			c3;

	MAR ← [rhArgReal, rArgReal + 0C],				c1;
	Q ← rhArgReal, CANCELBR[$,2],					c2;
	rMicaLength ← MD {final.micaLength},				c3;

	MAR ← [rhArgReal, rArgReal + 12],				c1;
	uLBArgRealHi ← Q, CANCELBR[$,2],				c2;
	Q ← MD {prior.micaLength},					c3;

	MAR ← [rhArgReal, rArgReal + 16],				c1;
	uLBPMicaLength ← Q, CANCELBR[$,2],				c2;
	Q ← MD {prior.whiteSpace},					c3;

	MAR ← [rhArgReal, rArgReal + 10],				c1;
	uLBPWhiteSpace ← Q, CANCELBR[$,2],				c2;
	rWhiteSpace ← MD {final.whiteSpace}, CALL[MapSrc],		c3;

{MapSrc subroutine starts in c1, ends in c2}
	Q ← MD {text[index]}, XHDisp, L1 ← 1,				c3, MapSrcRet[L0.LineBreak];

	MAR ← [rhArgReal, rArgReal + 0F], L3 ← 2, BRANCH[$,LBFirstEsc,2], c1;
	rCacheObj ← u3FFF, CANCELBR[LBReadyToLoop,2],			c2;
LBFirstEsc:
	rCacheObj ← u3FFF, CANCELBR[$,2],				c2;
LBReadyToLoop:
	rByteCount ← MD {final.byteCount}, L3Disp, GOTO[LBMainLoopCont], c3;

LBMainLoop:
	MAR ← rTextReal ← [rhTextReal, rTextReal + 1], BRANCH[$,LBNormalExit], c1;
LBMainRead:
	rCacheObj ← u3FFF, BRANCH[$,LBTextCross,1],			c2;
	Q ← MD {text[index]}, XHDisp,					c3;

LBMainLoopCont:
	rhLBFlags ← Q LRot4, XDisp, BRANCH[$,LBEscape,2],		c1;
	Q ← Q and rCacheObj, rhCacheObj ← uLBCacheHi, CANCELBR[$,0F],	c2;
	rCacheObj ← uLBCacheLo,						c3;

LBMapCache:
	Map ← Q ← [rhCacheObj, rCacheObj + Q], CarryBr,			c1;
	rCacheObj ← rhCacheObj + 1, LOOPHOLE[byteTiming], BRANCH[LBMapCacheCont,$], c2;
	rhCacheObj ← rCacheObj LRot0, rCacheObj ← 0, GOTO[LBMapCache],	c3;
LBMapCacheCont:
	rhCacheObj ← rCacheObj ← MD,					c3;

	MAR ← rCacheObj ← [rhCacheObj, Q + 0],				c1;
	Q ← ~u8000,							c2;
	Q ← MD and Q {font}, XHDisp,					c3;

	MAR ← [rhCacheObj, rCacheObj + 1], L4 ← 2{/3}, BRANCH[$,LBClearNotify,2], c1;
	[] ← Q xor uLBFont, NZeroBr, CANCELBR[LBTestFont,2],		c2;
LBClearNotify:
	[] ← Q xor uLBFont, NZeroBr, CANCELBR[$,2],			c2;
LBTestFont:
	Q ← MD {wordMetrics.micaLength}, BRANCH[$,LBInvalidCacheExit],	c3;

	rMicaLength ← rMicaLength + Q,					c1;
	[] ← rMicaLength - rMargin, CarryBr,				c2;
	Ybus ← rSpCount, YDisp, L4Disp, BRANCH[$,LBHyphenate],		c3;

	MAR ← [rhCacheObj, rCacheObj + 2], DISP4[LBCheckPunct,6],	c1;
	CANCELBR[LBUpdateMetrics,2],					c2, at[6,10,LBCheckPunct];
	rSpCount ← rSpCount or notPunctuationTRUE, CANCELBR[LBUpdateMetrics,2], c2, at[7,10,LBCheckPunct];
	rSpCount ← rSpCount and ~notPunctuationTRUE, CANCELBR[$,2],	c2, at[0E,10,LBCheckPunct];
LBUpdateMetrics:
	Q ← MD {wordMetrics.pixelLength},				c3;

	MAR ← [rhCacheObj, rCacheObj + 3],				c1;
	rBitLength ← rBitLength + Q, L4 ← 3, CANCELBR[$,3],		c2;
	Q ← MD {wordMetrics.byteCount},					c3;

	Xbus ← rhLBFlags, XDisp, L3 ← 9,				c1;
	rByteCount ← rByteCount + Q, BRANCH[LBLoopCheck,$,0B],		c2;
	rhSuffixChar ← suffixSpace, GOTO[LBSaveBreak],			c3;

LBEscape:
	L3 ← 9, DISP4[LBEsc,9],						c2;
	rhSuffixChar ← suffixSpace, GOTO[LBSaveBreak],			c3, at[escapeSpace,10,LBEsc];
	rhSuffixChar ← suffixZeroWidthSpace, GOTO[LBSaveBreak],		c3, at[escapeZeroWidthSpace,10,LBEsc];
	rReason ← reasonChangeBase, GOTO[LBExit],			c3, at[escapeChangeBase,10,LBEsc];

LBSaveBreak:
	uLBPMicaLength ← rMicaLength,					c1;
LBSvBkAtEnd:
	uLBPCtMinusIx ← rCtMinusIx, L1 ← 0,				c2;
	uLBPBitLength ← rBitLength,					c3;

	rSpCount ← rSpCount and ~notPunctuationTRUE,			c1;
	Q ← rSpCount or rhSuffixChar,					c2;
	uLBPSpCount ← Q,						c3;

	uLBPByteCount ← rByteCount, L3Disp,				c1;
	uLBPWhiteSpace ← rWhiteSpace, DISP4[LBSvBkRet],			c2;
LBSpace:
	rMicaLength ← rMicaLength + rMinSpMLength,			c3, at[9,10,LBSvBkRet];

	[] ← rMicaLength - rMargin - 1, CarryBr,			c1;
	rBitLength ← rBitLength + rMinSpPLength, BRANCH[$,LBSimpleMarginExit], c2;
	rSpCount ← rSpCount + spaceCountIncr,				c3;

	rByteCount ← rByteCount + 1,					c1;
	rWhiteSpace ← rWhiteSpace + rWhiteSpaceIncr,			c2;
LBLoopCheck:
	rCtMinusIx ← rCtMinusIx - 1, ZeroBr, GOTO[LBMainLoop],		c3, at[0B,10,LBSvBkRet];

LBHyphenate:
	MAR ← [rhCacheObj, rCacheObj + 4], L2Disp, BRANCH[$,LBUnableToBreakExit,7], c1;
	rMicaLength ← rMicaLength - Q, BRANCH[LBNoHyphen,$,2],		c2;
	rSylCount ← MD {sylableCount}, L2 ← 1,				c3;

	[] ← rSylCount, ZeroBr,						c1;
	Q ← uLBPWhiteSpace, BRANCH[$,LBNoSylables],			c2;
	rMinWidth ← rMargin - Q,					c3;

	Q ← uLBPMicaLength,						c1;
	[] ← Q - rMinWidth, CarryBr,					c2;
	rMinWidth ← rMargin, BRANCH[$,LBBreakOK],			c3;

	MAR ← rCacheObj ← [rhCacheObj, rCacheObj + 5],			c1;
	rMinWidth ← rMinWidth - rWhiteSpace, CANCELBR[$,2],		c2;
LBSylableLoop:
	rSylType ← MD {thisSylable.type}, XHDisp, BRANCH[$,LBSylLoopEnd], c3;

	MAR ← [rhCacheObj, rCacheObj + 1], BRANCH[$,LBSpecialGermanExit,2], c1;
	rSylType ← rSylType LRot8, CANCELBR[$,2],			c2;
	Q ← MD {thisSylable.micaLength},				c3;

	Q ← rMicaLength + Q,						c1;
	[] ← rMargin - Q, CarryBr,					c2;
	[] ← rSylType and 0F, ZeroBr, BRANCH[LBSkipSyl,$],		c3;

	[] ← rFit - Q, NegBr, L2Disp, BRANCH[$,LBFoundHard],		c1;
	[] ← Q - rMinWidth, CarryBr, BRANCH[$,LBSaveSyl],		c2;
	BRANCH[LBNextSyl,LBFoundFit],					c3;
LBSaveSyl:
	uLBPendSyl ← rCacheObj, rFit ← Q, L2 ← 0, BRANCH[$,LBFoundFit], c3;

LBNextSyl:
	MAR ← rCacheObj ← [rhCacheObj, rCacheObj + 3], GOTO[LBNextSylable], c1;
LBSkipSyl:
	MAR ← rCacheObj ← [rhCacheObj, rCacheObj + 3], CANCELBR[$,1],	c1;
LBNextSylable:
	rSylCount ← rSylCount - 1, ZeroBr, CANCELBR[LBSylableLoop,2],	c2;

LBSylLoopEnd:
	Q ← rFit, L2Disp, CANCELBR[$,3],				c1;
	rCacheObj ← uLBPendSyl, BRANCH[LBFoundSyl,$],			c2;
	rCtMinusIx ← uLBPCtMinusIx, GOTO[LBWholeWordBreak],		c3;
LBFoundSyl:
	Noop,								c3;

LBFoundFit:
	Noop,								c1;
	rhSuffixChar ← suffixHyphen, GOTO[LBHyphenateOK],		c2;
LBFoundHard:
	rhSuffixChar ← suffixHardHyphen, XLDisp, CANCELBR[$,1],		c2;
LBHyphenateOK:
	uLBPMicaLength ← rMicaLength ← Q, L3 ← 0{/1}, BRANCH[$,LBSetHard], c3;

	MAR ← [rhCacheObj, rCacheObj + 0], GOTO[LBHyphenateCont],	c1;
LBSetHard:
	MAR ← [rhCacheObj, rCacheObj + 0],				c1;
LBHyphenateCont:
	rSylByteCount ← 0FF,						c2;
	rSylByteCount ← rSylByteCount and MD {thisSylable.byteCount},	c3;

	MAR ← [rhCacheObj, rCacheObj + 2],	 			c1;
	rByteCount ← rByteCount + rSylByteCount, CANCELBR[$,2],		c2;
	rSylBitLength ← MD {thisSylable.pixelLength},			c3;

	rBitLength ← rBitLength + rSylBitLength, CALL[LBSvBkAtEnd],	c1;
{	uLBPCtMinusIx ← rCtMinusIx, L1 ← 0,				c2;
	uLBPBitLength ← rBitLength,					c3;

	rSpCount ← rSpCount and ~notPunctuationTRUE,			c1;
	Q ← rSpCount or rhSuffixChar,					c2;
	uLBPSpCount ← Q,						c3;

	uLBPByteCount ← rByteCount, L3Disp,				c1;
	uLBPWhiteSpace ← rWhiteSpace, DISP4[LBSvBkRet],			c2;}
	Q ← rhLBHyphenPL, GOTO[LBComputeBackup],			c3, at[0,10,LBSvBkRet];
	Q ← 0,								c3, at[1,10,LBSvBkRet];

LBComputeBackup:
	MAR ← [rhCacheObj, rCacheObj + 1],				c1;
	rBitLength ← Q - rSylBitLength, CANCELBR[$,2],			c2;
	rMicaLength ← MD {thisSylable.micaLength},			c3;

	rSpCount ← 0, rhSuffixChar ← suffixNull,			c1;
	rArgReal ← uLBArgRealLo,					c2;
	rhArgReal ← uLBArgRealHi,					c3;

	MAR ← [rhArgReal, rArgReal + 8], L3Disp,			c1;
	rByteCount ← - rSylByteCount, BRANCH[$,LBBackupHard,2],		c2;
	Q ← MD {hyphenMicaLength}, GOTO[LBFinishBackup],		c3;
LBBackupHard:
	Q ← 0,								c3;

LBFinishBackup:
	rMicaLength ← Q - rMicaLength,					c1;
	rWhiteSpace ← 0,						c2;
	rReason ← reasonMargin, GOTO[LBStoreFinalCont],			c3;

LBNoSylables:
	rCtMinusIx ← uLBPCtMinusIx, CANCELBR[LBWholeWordBreak,1],	c3;

LBBreakOK:
	Noop,								c1;
	Noop,								c2;
LBNoHyphen:
	rCtMinusIx ← uLBPCtMinusIx, GOTO[LBWholeWordBreak],		c3;

LBSimpleMarginExit:
	rCtMinusIx ← uLBPCtMinusIx,					c3;

LBWholeWordBreak:
	rCtMinusIx ← rCtMinusIx - 1,					c1;
	rMicaLength ← 0,						c2;
	rBitLength ← 0,							c3;

	rSpCount ← 0, rhSuffixChar ← suffixNull,			c1;
	rByteCount ← 0,							c2;
	rWhiteSpace ← 0,						c3;

	rReason ← reasonMargin, L1Disp, GOTO[LBStoreFinal],		c1;

LBInvalidCacheExit:
	rReason ← reasonInvalidCache, GOTO[LBStoreFinal],		c1;

LBContiguousExit:
	rReason ← reasonContiguousWords, CANCELBR[$,2],			c2, at[0F,10,LBCheckPunct];
	rMicaLength ← rMicaLength - Q, GOTO[LBExit],			c3;

LBUnableToBreakExit:
	rReason ← reasonUnableToBreak, CANCELBR[LBExit3,3],		c2;

LBNormalExit:
	rReason ← reasonNormal, CANCELBR[LBExit3,3],			c2;
LBSpecialGermanExit:
	rReason ← reasonSpecialGermanCase, CANCELBR[$,3],		c2;
LBExit3:
	Noop,								c3;

LBExit:	Noop,								c1;
LBStoreFinal:
	rArgReal ← uLBArgRealLo, BRANCH[$,LBReadPriorIndex],		c2;
	rhArgReal ← uLBArgRealHi, GOTO[LBStoreFinalCont],		c3;
LBReadPriorIndex:
	rhArgReal ← uLBArgRealHi,					c3;

	MAR ← [rhArgReal, rArgReal + 11],				c1;
	uLBTextCount ← 0, CANCELBR[$,2],				c2;
	rCtMinusIx ← ~MD {prior.index},					c3;

LBStoreFinalCont:
	MAR ← [rhArgReal, rArgReal + 0C],				c1;
	MDR ← rMicaLength {final.micaLength}, CANCELBR[$,2], LOOPHOLE[wok], c2;
	rSpCount ← rSpCount or rhSuffixChar,				c3;

	MAR ← [rhArgReal, rArgReal + 0D],				c1;
	MDR ← rBitLength {final.bitLength}, CANCELBR[$,2], LOOPHOLE[wok], c2;
	Q ← uLBTextCount,						c3;

	MAR ← [rhArgReal, rArgReal + 0E],				c1;
	MDR ← rSpCount {final.count}, CANCELBR[$,2], LOOPHOLE[wok],	c2;
	Q ← Q - rCtMinusIx,						c3;

	MAR ← [rhArgReal, rArgReal + 0B],				c1;
	MDR ← Q {final.index}, CANCELBR[$,2], LOOPHOLE[wok],		c2;
	Q ← uLBTextCount,						c3;

	MAR ← [rhArgReal, rArgReal + 0F],				c1;
	MDR ← rByteCount {final.byteCount}, CANCELBR[$,2], LOOPHOLE[wok], c2;
	rCtMinusIx ← uLBPCtMinusIx,					c3;

	MAR ← [rhArgReal, rArgReal + 10], L1Disp,			c1;
	MDR ← rWhiteSpace {final.whiteSpace}, BRANCH[$,LBRestoreRegs,2], c2;
	Q ← Q - rCtMinusIx,						c3;

	MAR ← [rhArgReal, rArgReal + 11],				c1;
	MDR ← Q {prior.index}, CANCELBR[$,2], LOOPHOLE[wok],		c2;
	Q ← uLBPMicaLength,						c3;

	MAR ← [rhArgReal, rArgReal + 12],				c1;
	MDR ← Q {prior.micaLength}, CANCELBR[$,2], LOOPHOLE[wok],	c2;
	Q ← uLBPBitLength,						c3;

	MAR ← [rhArgReal, rArgReal + 13],				c1;
	MDR ← Q {prior.bitLength}, CANCELBR[$,2], LOOPHOLE[wok],	c2;
	Q ← uLBPSpCount,						c3;

	MAR ← [rhArgReal, rArgReal + 14],				c1;
	MDR ← Q {prior.count}, CANCELBR[$,2], LOOPHOLE[wok],		c2;
	Q ← uLBPByteCount,						c3;

	MAR ← [rhArgReal, rArgReal + 15],				c1;
	MDR ← Q {prior.byteCount}, CANCELBR[$,2], LOOPHOLE[wok],	c2;
	Q ← uLBPWhiteSpace,						c3;

	MAR ← [rhArgReal, rArgReal + 16],				c1;
	MDR ← Q {prior.whiteSpace}, CANCELBR[$,3], LOOPHOLE[wok],	c2;
LBRestoreRegs:
	L ← UrL,							c3;

	G ← UrG,							c1;
	PC ← UrPC, push, GOTO[LBDone],					c2;

LBFastExit:
	rReason ← reasonNormal,						c1;
	push,								c2;
LBDone:	STK ← TOS, r0100 ← 0FF + 1, pop, GOTO[Bank1NxtInstc1],		c3;

{page cross handling}

LBTextCross:
	rCacheObj ← rByteCount {save in temp, since rVirtualL = rByteCount}, c3;

	rVirtualL ← uLBTextRealLo, L3 ← 2,				c1;
	Q ← 0FF + 1,							c2;
	rVirtualL ← rVirtualL + Q, CarryBr,				c3;

LBTextRemap:
	Map ← uLBTextRealLo ← [rhVirtualH, rVirtualL], BRANCH[$,LBUpdateHighCont], c1, at[2,10,LBUpdateHighRet];
	rByteCount ← rCacheObj, {restore from temp}			c2;
	rhTextReal ← rTextReal ← MD,					c3;

	MAR ← rTextReal ← [rhTextReal, 0+0], GOTO[LBMainRead],		c1;

LBUpdateHigh:
	Noop,								c1;
LBUpdateHighCont:
	Q ← rhVirtualH + 1, LOOPHOLE[byteTiming], L3Disp,		c2;
	rhVirtualH ← Q LRot0, DISP4[LBUpdateHighRet],			c3;