TSBreakUpImpl.mesa
Breaking lists into lists of boxes
Michael Plass, November 2, 1982 10:34 am
DIRECTORY TSTypes, TSObject, TSFont, TSGlue, TSOps;
TSBreakUpImpl:
CEDAR
PROGRAM
IMPORTS TSObject, TSTypes, TSFont, TSGlue, TSOps
EXPORTS TSOps =
BEGIN OPEN TSTypes;
BreakUp:
PUBLIC
PROCEDURE [
list: TSObject.ItemList,
direction: TSObject.Direction,
size: Dimn
] RETURNS [new: TSObject.ItemList] = {
brokenList: REF BrokenListRec ← NEW[BrokenListRec];
opposite: Direction ←
SELECT direction
FROM
right => left, down => up, left => right, up => down, ENDCASE => ERROR;
brokenList.source ← list.CreateReader[];
brokenList.direction ← direction;
brokenList.size ← [nilDimn, nilDimn, nilDimn, nilDimn];
brokenList.size[direction] ← size;
brokenList.size[opposite] ← zeroDimn;
new ← TSObject.CreateItemList[
producer: BrokenListProducer,
writerData: brokenList
];
};
BrokenListRec:
TYPE =
RECORD [
source: TSObject.ListReader,
direction: TSObject.Direction,
size: Dimensions,
front: LIST OF REF ANY ← NIL
];
BrokenListProducer: TSObject.ProducerProc = {
r: REF BrokenListRec ← NARROW[listWriter.writerData];
IF r.source.End[]
THEN {
listWriter.ProduceEnd[];
r.source.DestroyReader[]; r.source ← NIL
}
ELSE {
amount: INT;
rear: LIST OF REF ANY;
tempReader: TSObject.ListReader ← r.source.CopyReader[];
[amount, rear] ← MeasureOff[tempReader, r.direction, r.size[r.direction], r.front];
tempReader.DestroyReader[];
listWriter.ProduceItem[TSOps.Package[
source: r.source,
direction: r.direction,
desired: r.size,
itemCount: amount,
front: r.front,
rear: rear
]];
r.front ← Postbreak[r.source];
};
};
Postbreak:
PROCEDURE [
source: TSObject.ListReader
] RETURNS [postbreak: LIST OF REF ANY ← NIL] = {
SELECT source.CurrentTag[]
FROM
space => {
postbreak ← source.listParameter[leftfill];
source.Next[];
WHILE source.CurrentTag[] = space DO source.Next[] ENDLOOP;
};
hyphen => {
postbreak ← source.listParameter[leftfill];
source.Next[];
};
exception => {
SELECT
TRUE
FROM
ISTYPE[source.CurrentItem[], TSObject.Kerf] => {
postbreak ← NARROW[source.CurrentItem[], TSObject.Kerf]^.postbreak;
source.Next[]
};
ENDCASE => {};
};
ENDCASE;
};
MeasureOff:
PROCEDURE [
list: TSObject.ListReader,
direction: TSObject.Direction,
size: Dimn,
front: LIST OF REF ANY ← NIL
]
RETURNS [
bestNumberOfItems: INT ← 0,
rear: LIST OF REF ANY
] = {
totGlue: TSGlue.GlueSum ← TSGlue.zeroGlueSum;
AddGlue:
PROC [glue: TSGlue.Glue] =
INLINE {
OPEN TSGlue;
totGlue.space.texPts ← totGlue.space.texPts + glue.space.texPts;
SELECT
ABS[glue.stretch.texPts]
FROM
< fil.texPts => totGlue.stretch[0].texPts ← totGlue.stretch[0].texPts + glue.stretch.texPts;
< fill.texPts => totGlue.stretch[1].texPts ← totGlue.stretch[1].texPts + glue.stretch.texPts;
< filll.texPts => totGlue.stretch[2].texPts ← totGlue.stretch[2].texPts + glue.stretch.texPts;
ENDCASE => totGlue.stretch[3].texPts ← totGlue.stretch[3].texPts + glue.stretch.texPts;
SELECT
ABS[glue.shrink.texPts]
FROM
< fil.texPts => totGlue.shrink[0].texPts ← totGlue.shrink[0].texPts + glue.shrink.texPts;
< fill.texPts => totGlue.shrink[1].texPts ← totGlue.shrink[1].texPts + glue.shrink.texPts;
< filll.texPts => totGlue.shrink[2].texPts ← totGlue.shrink[2].texPts + glue.shrink.texPts;
ENDCASE => totGlue.shrink[3].texPts ← totGlue.shrink[3].texPts + glue.shrink.texPts;
};
itemCount: INT ← 0;
prebreak: LIST OF REF ANY;
lowBad: Badness ← infBadness*2;
oldTot: TSGlue.GlueSum;
overfull: BOOLEAN ← FALSE;
opposite: TSObject.Direction ←
SELECT direction
FROM
right => left, down => up, left => right, up => down, ENDCASE => ERROR;
CalculateBadness:
PROC [hyphen:
BOOLEAN ←
FALSE] =
INLINE {
glueSet: TSGlue.GlueSet ← TSGlue.SetGlue[size, TSGlue.GlueFromSum[totGlue]];
curBad: Badness;
overfull ← (glueSet = TSGlue.overfullGlueSet);
curBad ← TSGlue.GlueBadness[glueSet];
IF curBad < lowBad
THEN {
lowBad ← curBad; bestNumberOfItems ← itemCount; rear ← prebreak;
IF hyphen
THEN rear ←
CONS[
NEW[TSObject.BoxRec ← [
list.currentFont.CharDimensions['-],
char [list.currentFont, '-]
]], rear]
};
totGlue ← oldTot;
};
MeasureException:
PROC[x:
REF
ANY] = {
SELECT
TRUE
FROM
ISTYPE[x, TSObject.Glue] => {
g: TSObject.Glue ← NARROW[x];
AddGlue[g^];
};
ISTYPE[x, TSObject.Box] => {
b: TSObject.Box ← NARROW[x];
totGlue.space ← AddDimn[totGlue.space, AddDimn[b.extent[opposite], b.extent[direction]]];
};
ISTYPE[x, TSObject.Kerf] => {
p: LIST OF REF ANY;
oldTot ← totGlue;
prebreak ← p ← NARROW[x, TSObject.Kerf].prebreak;
WHILE p #
NIL
DO
MeasureException[p.first];
p ← p.rest;
ENDLOOP;
CalculateBadness[];
totGlue ← oldTot;
p ← NARROW[x, TSObject.Kerf].join;
WHILE p #
NIL
DO
MeasureException[p.first];
p ← p.rest;
ENDLOOP;
};
ISTYPE[x, TSObject.Kern] => {
totGlue.space ← AddDimn[totGlue.space, NARROW[x, TSObject.Kern]^];
};
ENDCASE => {};
};
WHILE front #
NIL
DO
MeasureException[front.first];
front ← front.rest;
ENDLOOP;
UNTIL list.End[]
OR overfull
DO
SELECT list.CurrentTag[]
FROM
char => {
extent: Dimensions ← list.currentFont.CharDimensions[list.CurrentChar[]];
totGlue.space ← AddDimn[totGlue.space, AddDimn[extent[direction], extent[opposite]]];
list.Next[];
itemCount ← itemCount + 1;
};
space => {
oldTot ← totGlue;
prebreak ← list.listParameter[rightfill]; -- measure right glue
FOR p:
LIST
OF
REF
ANY ← prebreak, p.rest
UNTIL p=
NIL
DO
MeasureException[p.first];
ENDLOOP;
CalculateBadness[];
totGlue ← oldTot;
WHILE list.CurrentTag[] = space
DO
AddGlue[list.currentFont.SpaceGlue[]];
list.Next[];
itemCount ← itemCount + 1;
ENDLOOP;
};
hyphen => {
extent: Dimensions ← list.currentFont.CharDimensions['-];
oldTot ← totGlue;
totGlue.space ← AddDimn[totGlue.space, AddDimn[extent[direction], extent[opposite]]];
prebreak ← list.listParameter[rightfill]; -- measure right glue
FOR p:
LIST
OF
REF
ANY ← prebreak, p.rest
UNTIL p=
NIL
DO
MeasureException[p.first];
ENDLOOP;
CalculateBadness[TRUE];
totGlue ← oldTot;
list.Next[];
itemCount ← itemCount + 1;
};
exception => {
MeasureException[list.CurrentItem[]];
list.Next[];
itemCount ← itemCount + 1;
};
ENDCASE => ERROR;
ENDLOOP;
IF list.End[]
THEN {
prebreak ← NIL;
CalculateBadness[];
};
};
END.
Michael Plass, September 1, 1982 9:35 pm: Put in calls to TSObject.DestroyReader.
Michael Plass, November 2, 1982 10:34 am. CEDARized.