TSJaMPageBuilderImpl.mesa
Edited by: Maxwell, January 25, 1983 2:39 pm
Michael Plass, April 2, 1985 2:13:04 pm PST
Last Edited by: Beach, May 7, 1984 4:13:18 pm PDT
DIRECTORY
Atom,
TSTypes,
TSObject,
TSOps,
TSDumper,
TSFont,
TSGlue,
TSOutput,
NodeStyle,
NodeStyleWorks,
TJaM,
Rope,
TSJaMPageBuilder
;
TSJaMPageBuilderImpl:
CEDAR PROGRAM
IMPORTS
Atom, TSTypes, TSObject, TSOps, TSDumper, TSFont, TSOutput, NodeStyle, NodeStyleWorks, TJaM
EXPORTS TSJaMPageBuilder =
BEGIN OPEN TSTypes;
ROPE: TYPE = Rope.ROPE;
Frame: TYPE = TJaM.Frame;
Handle: TYPE = REF TPStateRec;
TPStateRec:
TYPE =
RECORD [
pageReader: TSObject.ListReader,
currentMarks: TSObject.MarkList,
topMargin, leftMargin, pageHeight, paperHeight, paperWidth: Dimn,
columns: NAT,
output: TSOutput.Handle,
curFont: TSFont.Ref,
styleName: ATOM,
documentName: ROPE,
aborted: BOOLEAN ← FALSE
];
AbortCheck:
SIGNAL
RETURNS [stop:
BOOL] ~
CODE;
RunPageBuilder:
PUBLIC
PROCEDURE [
galley: TSObject.ItemList,
style: NodeStyle.Ref,
output: TSOutput.Handle,
abortCheckProc: TSJaMPageBuilder.AbortCheckProc ← NIL,
documentName: Rope.ROPE ← NIL -- only a hint
]
RETURNS [aborted: BOOLEAN] = {
styleName: ATOM ~ style.GetStyleName[];
frame: Frame ← NodeStyleWorks.GetFrame[style: style, styleName: styleName, kind: print];
handle: Handle ← NEW[TPStateRec];
leadedGalley: TSObject.ItemList ← TSOps.InsertLeading[galley];
handle.styleName ← styleName;
RegisterJaMProcs[frame];
handle.paperHeight ← Pt[style.GetPageLength[]];
handle.paperWidth ← Pt[style.GetPageWidth[]];
handle.pageHeight ← Pt[style.GetPageLength[]-style.GetTopMargin[]-style.GetHeaderMargin[]-style.GetFooterMargin[]-style.GetBottomMargin[]];
handle.topMargin ← Pt[style.GetTopMargin[]];
handle.leftMargin ← Pt[style.GetLeftMargin[]];
handle.columns ← style.GetColumns[];
handle.documentName ← documentName;
handle.pageReader ← TSOps.BreakUp[
list: TSOps.InsertLeading[galley],
direction: down,
size: handle.pageHeight
].CreateReader[];
handle.output ← output;
frame.propList ← Atom.PutPropOnList[frame.propList, $PageBuilderHandle, handle];
TJaM.Execute[frame, TJaM.CvX[pageBuilderName] ! AbortCheck => {RESUME[abortCheckProc[]]}];
frame.propList ← Atom.RemPropFromList[frame.propList, $PageBuilderHandle];
NodeStyleWorks.FreeFrame[frame: frame, styleName: styleName, kind: print];
aborted ← handle.aborted;
};
HandleFromFrame:
PROC [f: Frame]
RETURNS [Handle] ~ {
RETURN [NARROW[Atom.GetPropFromList[f.propList, $PageBuilderHandle]]]
};
pageBuilderName: ATOM = Atom.MakeAtom["PageBuilder"];
PopList:
PROCEDURE [f: Frame]
RETURNS [itemList: TSObject.ItemList] =
BEGIN
list: LIST OF REF ANY ← NIL;
count: INT ← TJaM.PopInt[f];
THROUGH [0..count)
DO
item: REF ANY ← TJaM.Pop[f];
IF item # NIL THEN list ← CONS[item, list];
ENDLOOP;
itemList ← TSObject.ItemListFromExplicitList[list];
END;
Page:
PROCEDURE [f: Frame] =
BEGIN -- Pushes the next page box onto the stack
handle: Handle ← HandleFromFrame[f];
handle.aborted ← SIGNAL AbortCheck[];
DO
-- until we find a page box or empty the page list
IF handle.aborted
OR handle.pageReader =
NIL OR handle.pageReader.End[]
THEN {
TJaM.PushBool[f, FALSE];
IF handle.pageReader # NIL THEN handle.pageReader.DestroyReader[];
handle.pageReader ← NIL;
EXIT
}
ELSE {
IF
ISTYPE[handle.pageReader.CurrentItem[], TSObject.MarkList]
THEN {
thisPageMarks: TSObject.MarkList ← NARROW[handle.pageReader.CurrentItem[], TSObject.MarkList];
handle.currentMarks ← MergeMarkLists[thisPageMarks, handle.currentMarks];
handle.pageReader.Next[];
LOOP;
};
TJaM.Push[f, handle.pageReader.CurrentItem[]];
handle.pageReader.Next[];
TJaM.PushBool[f, TRUE];
EXIT
};
ENDLOOP;
END;
ShipOut:
PROCEDURE [f: Frame] =
BEGIN -- Sends a constructed page to the outside world
handle: Handle ← HandleFromFrame[f];
item: REF ANY ← TJaM.Pop[f];
handle.output.newPageProc[handle.output];
WITH item
SELECT
FROM
box: TSObject.Box => {
IF handle.output.pageSizeProc #
NIL
THEN
handle.output.pageSizeProc[
handle.output, handle.paperHeight, handle.paperWidth
];
handle.output.BoxOut[
xRef: handle.leftMargin,
yRef: SubDimn[handle.paperHeight, handle.topMargin],
box: box^
];
};
ENDCASE => NULL;
END;
BoxFromHList:
PROCEDURE [list: TSObject.ItemList]
RETURNS [box: TSObject.Box] = {
source: TSObject.ListReader ← list.CreateReader[];
box ← TSOps.Package[source: source, direction: right, desired: [zeroDimn,nilDimn,nilDimn,nilDimn]].box;
source.DestroyReader[];
};
Columns:
PROCEDURE [f: Frame] =
BEGIN
handle: Handle ← HandleFromFrame[f];
TJaM.PushInt[f, handle.columns];
END;
DocumentName:
PROCEDURE [f: Frame] =
BEGIN
handle: Handle ← HandleFromFrame[f];
TJaM.PushRope[f, handle.documentName];
END;
TextBox:
PROCEDURE [f: Frame] =
BEGIN
handle: Handle ← HandleFromFrame[f];
rope: ROPE ← TJaM.PopRope[f];
IF handle.curFont = NIL THEN handle.curFont ← TSFont.Lookup["Helvetica"];
TJaM.Push[f, BoxFromHList[TSOps.ItemListFromRope[handle.curFont, rope]]];
END;
TextFont:
PROCEDURE [f: Frame] =
BEGIN
handle: Handle ← HandleFromFrame[f];
fontSize: Dimn ← RealDimn[TJaM.PopReal[f], pt];
fontName: ROPE ← TJaM.PopRope[f];
handle.curFont ← TSFont.Lookup[fontName, fontSize];
END;
Vbox:
PROCEDURE [f: Frame] =
BEGIN
source: TSObject.ListReader ← PopList[f].CreateReader[];
box: TSObject.Box ← TSOps.Package[
source: source,
direction: down,
desired: [nilDimn, nilDimn, zeroDimn, nilDimn]
].box;
TJaM.Push[f, box];
source.DestroyReader[];
END;
Hbox:
PROCEDURE [f: Frame] =
BEGIN
TJaM.Push[f, BoxFromHList[PopList[f]]];
END;
VboxTo:
PROCEDURE [f: Frame] =
BEGIN
size: Dimn ← RealDimn[TJaM.PopReal[f], pt];
source: TSObject.ListReader ← PopList[f].CreateReader[];
TJaM.Push[f, TSOps.Package[
source: source,
direction: down,
desired: [nilDimn, nilDimn, zeroDimn, size]
].box];
source.DestroyReader[];
END;
HboxTo:
PROCEDURE [f: Frame] =
BEGIN
size: Dimn ← RealDimn[TJaM.PopReal[f], pt];
source: TSObject.ListReader ← PopList[f].CreateReader[];
TJaM.Push[f, TSOps.Package[
source: source,
direction: right,
desired: [zeroDimn, size, nilDimn, nilDimn]
].box];
source.DestroyReader[];
END;
fillGlue: TSObject.Glue = NEW[TSGlue.Glue ← [zeroDimn, TSGlue.fill, zeroDimn]];
Fill:
PROCEDURE [f: Frame] =
BEGIN
TJaM.Push[f, fillGlue];
END;
This proc can dump boxes, for use in debugging
DumpBox:
PROCEDURE [f: Frame] =
BEGIN
TSDumper.DumpList[TSObject.SingletonList[TJaM.Pop[f]]];
END;
emptyBox: TSObject.Box = NEW[TSObject.BoxRec ← [[zeroDimn, zeroDimn, zeroDimn, zeroDimn], empty[]]];
GetMark:
PROCEDURE [f: Frame] = {
handle: Handle ← HandleFromFrame[f];
markKind: ROPE ← TJaM.PopRope[f];
IF handle.currentMarks #
NIL
THEN {
markAtom: ATOM ← Atom.MakeAtom[markKind];
l: REF TSObject.MarkListItem ← handle.currentMarks;
UNTIL l =
NIL
OR l.markKind = markAtom
DO
l ← l.link;
ENDLOOP;
IF l = NIL THEN TJaM.Push[f, emptyBox]
ELSE TJaM.Push[f, l.markValue];
}
ELSE TJaM.Push[f, emptyBox];
};
GetFirstMark:
PROCEDURE [f: Frame] = {
handle: Handle ← HandleFromFrame[f];
markKind: ROPE ← TJaM.PopRope[f];
IF handle.currentMarks #
NIL
THEN {
markAtom: ATOM ← Atom.MakeAtom[markKind];
l: REF TSObject.MarkListItem ← handle.currentMarks;
last: REF TSObject.MarkListItem ← NIL;
UNTIL l =
NIL
DO
IF l.markKind = markAtom THEN last ← l;
l ← l.link;
ENDLOOP;
IF last = NIL THEN TJaM.Push[f, emptyBox]
ELSE TJaM.Push[f, last.markValue];
}
ELSE TJaM.Push[f, emptyBox];
};
MergeMarkLists:
PROCEDURE [new, old: TSObject.MarkList]
RETURNS [TSObject.MarkList] = {
Merge the new and old lists of marks into one list with old duplicates eliminated, preserving order.
p, q, r: TSObject.MarkList;
Using a niave n**2 search, eliminate duplicates from the old list.
p ← old;
UNTIL p =
NIL
DO
r ← p;
q ← p.link;
UNTIL q =
NIL
DO
IF p.markKind = q.markKind THEN r.link ← q.link ELSE r ← q;
q ← q.link;
ENDLOOP;
p ← p.link;
ENDLOOP;
Find the end of the new list to concatenate the old one.
p ← new;
UNTIL p =
NIL
OR p.link =
NIL
DO
p ← p.link;
ENDLOOP;
IF p = NIL THEN new ← old ELSE p.link ← old;
RETURN [new];
};
ExchBox:
PROCEDURE [f: Frame] = {
item1: REF ANY ← TJaM.Pop[f];
item2: REF ANY ← TJaM.Pop[f];
TJaM.Push[f, item1];
TJaM.Push[f, item2];
};
RegisterJaMProcs:
PROCEDURE [f: Frame] =
BEGIN OPEN NodeStyleWorks;
RegisterStyleCommand[f, Atom.MakeAtom[".page"], Page]; -- -> <pagebox> .true . OR -> .false
RegisterStyleCommand[f, Atom.MakeAtom[".getmark"], GetMark]; -- -> <pagebox> (markkind) -> <pagebox> <markbox>
RegisterStyleCommand[f, Atom.MakeAtom[".getfirstmark"], GetFirstMark]; -- -> <pagebox> (markkind) -> <pagebox> <markbox>
RegisterStyleCommand[f, Atom.MakeAtom[".columns"], Columns]; -- -> <pagebox> .true . OR -> .false
RegisterStyleCommand[f, Atom.MakeAtom[".shipout"], ShipOut]; -- <box> -> . The box is sent out
RegisterStyleCommand[f, Atom.MakeAtom[".documentname"], DocumentName]; -- -> string .
RegisterStyleCommand[f, Atom.MakeAtom[".textbox"], TextBox]; -- string -> <box> . uses current font
RegisterStyleCommand[f, Atom.MakeAtom[".textfont"], TextFont]; -- fontnamestring fontpointsize -> . sets current font
RegisterStyleCommand[f, Atom.MakeAtom[".vbox"], Vbox]; -- <item1> <item2> ... <itemn> n -> <box> .
RegisterStyleCommand[f, Atom.MakeAtom[".hbox"], Hbox]; -- <item1> <item2> ... <itemn> n -> <box> .
RegisterStyleCommand[f, Atom.MakeAtom[".vboxto"], VboxTo]; -- <item1> <item2> ... <itemn> n height -> <box> .
RegisterStyleCommand[f, Atom.MakeAtom[".hboxto"], HboxTo]; -- <item1> <item2> ... <itemn> n height -> <box> .
RegisterStyleCommand[f, Atom.MakeAtom[".fill"], Fill]; -- -> <fillglue> .
RegisterStyleCommand[f, Atom.MakeAtom[".dumpbox"], DumpBox]; -- <box> -> .
RegisterStyleCommand[f, Atom.MakeAtom[".exchbox"], ExchBox]; -- <box1> <box2> -> <box2> <box1>
END;
END.
Michael Plass, September 1, 1982 9:21 pm: Put in calls to TSObject.DestroyReader.
Michael Plass, November 2, 1982 2:39 pm. Tioga formatted.
Michael Plass, November 12, 1982 10:11 am. pZone.
Michael Plass, November 16, 1982 2:36 pm. Changed to use some of the page layout parameters.
Michael Plass, November 17, 1982 9:34 am. Fixed frame and style stuff.
Michael Plass, November 17, 1982 11:13 am. Fixed bug that prevented .page from working after the end marker was sent.
Michael Plass, February 15, 1983 1:04 pm. Removed dependency on JaMTypeScript.
Rick Beach, May 17, 1983 10:17 am. Added .getmark routines., Rick
Edited on May 17, 1983 10:16 am, by Beach
Added .exchbox to permit a layout style to get a page, then get headers which must precede the page.
Edited on May 24, 1983 8:52 am, by Beach
Added MergeMarkLists to properly maintain a page history of marks., MergeMarkLists
Edited on January 10, 1984 9:33 am, by Plass
Added calls to TSWrecker.
Michael Plass, March 12, 1985 2:22:10 pm PST
JaM --> TJaM
changes to: DIRECTORY, TSJaMPageBuilderImpl, RunPageBuilder, PopRope, PushRope, Page, Columns, TextFont, Vbox, Hbox, VboxTo, HboxTo