{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;