=
BEGIN OPEN TableBase, TableLayout;
LayoutTable:
PUBLIC PROCEDURE [table: RefTable, maxX, maxY, suggestedX, suggestedY: TSTypes.Dimn ← TSTypes.nilDimn]
RETURNS [extent: TSTypes.Dimensions] = {
IF table.branch =
NIL
OR table.tableGrid =
NIL
THEN
ERROR ImplementationError["Malformed table does not have proper data structure"];
TableConstraints.SolveConstraints[table];
extent ← [TSTypes.zeroDimn, table.colGridPositions.grid[table.columnGrids],
table.rowGridPositions.grid[FIRST[TableBase.GridNumber]], TSTypes.zeroDimn];
};
PaintTable:
PUBLIC PROCEDURE [table: RefTable, handle: TSOutput.Handle, originX, originY: TSTypes.Dimn, extent: TSTypes.Dimensions] = {
paint the table to an output sink handle positioned with bottom left corner at (originX, originY) to fit the given extent.
PaintTableBox: EnumeratedEntryProc = {
paint the table box with top left corner (box.x, box.y) relative to (originX, originY)
WITH entry
SELECT
FROM
box: RefTableBox => {
IF box.tsObject #
NIL
THEN
box.tsObject.paintProc[box.tsObject, handle, originX.AddDimn[box.x],
originY.AddDimn[box.y], box.nodeExtents];
};
rule: RefTableRule => {
thickness: TSTypes.Dimn;
length: TSTypes.Dimn;
x,y: TSTypes.Dimn;
SELECT rule.orientation
FROM
horizontal => {
thickness ← rule.thickness;
length ← table.colGridPositions[rule.right].SubDimn[table.colGridPositions[rule.left]].AddDimn[rule.thickness];
};
vertical => {
thickness ← table.rowGridPositions[rule.top].SubDimn[table.rowGridPositions[rule.bottom]].AddDimn[rule.thickness];
length ← rule.thickness;
};
ENDCASE => ERROR;
x ← table.colGridPositions[rule.left].SubDimn[rule.thickness.DivDimn[2]];
y ← table.rowGridPositions[rule.bottom].SubDimn[rule.thickness.DivDimn[2]];
handle.ruleProc[self~handle, leftX~originX.AddDimn[x], bottomY~originY.AddDimn[y], width~length, height~thickness];
};
background: RefTableBackground => NULL; -- there shouldn't be any of these, but ...
ENDCASE => ERROR;
};
IF table.branch =
NIL
OR table.tableGrid =
NIL
THEN
ERROR ImplementationError["Malformed table does not have proper data structure"];
IF table.backgrounds #
NIL
THEN {
FOR b:
LIST
OF RefTableBackground ← table.backgrounds, b.rest
WHILE b #
NIL
DO
background: RefTableBackground ← b.first;
length: TSTypes.Dimn ~ table.colGridPositions[background.right].SubDimn[table.colGridPositions[background.left]];
thickness: TSTypes.Dimn ~ table.rowGridPositions[background.top].SubDimn[table.rowGridPositions[background.bottom]];
x: TSTypes.Dimn ~ table.colGridPositions[background.left];
y: TSTypes.Dimn ~ table.rowGridPositions[background.bottom];
handle.colorProc[
self~handle,
hue~background.hue,
saturation~background.saturation,
brightness~background.brightness]; -- grey
handle.ruleProc[self~handle, leftX~originX.AddDimn[x], bottomY~originY.AddDimn[y], width~length, height~thickness];
handle.colorProc[self~handle, hue~0.0, saturation~0.0, brightness~0.0]; -- black
ENDLOOP;
};
IF table.gridOverlayThickness # TSTypes.nilDimn
THEN {
Put out some interesting grid lines
halfThickness: TSTypes.Dimn ~ table.gridOverlayThickness.DivDimn[2];
FOR i: TableBase.GridNumber
IN [0..table.rowGrids]
DO
handle.colorProc[
self~handle,
hue~table.gridOverlayHue,
saturation~table.gridOverlaySaturation,
brightness~table.gridOverlayBrightness]; -- grey
handle.ruleProc[
self~handle, leftX~originX.SubDimn[halfThickness],
bottomY~originY.AddDimn[table.rowGridPositions.grid[i]].SubDimn[halfThickness],
width~extent[right].AddDimn[table.gridOverlayThickness],
height~table.gridOverlayThickness];
handle.colorProc[self~handle, hue~0.0, saturation~0.0, brightness~0.0]; -- black
ENDLOOP;
FOR i: TableBase.GridNumber
IN [0..table.columnGrids]
DO
handle.colorProc[
self~handle,
hue~table.gridOverlayHue,
saturation~table.gridOverlaySaturation,
brightness~table.gridOverlayBrightness]; -- grey
handle.ruleProc[
self~handle,
leftX~originX.AddDimn[table.colGridPositions.grid[i]].SubDimn[halfThickness],
bottomY~originY.SubDimn[halfThickness],
width~table.gridOverlayThickness,
height~extent[up].AddDimn[table.gridOverlayThickness]];
handle.colorProc[self~handle, hue~0.0, saturation~0.0, brightness~0.0]; -- black
ENDLOOP;
};
EnumerateByRows[table, PaintTableBox];
};
AlignExtents:
PUBLIC
PROCEDURE [table: TableBase.RefTable, box: TableBase.RefTableBox]
RETURNS [extents: TSTypes.Dimensions] ~
TRUSTED {
IF box.nodeExtentsValid THEN RETURN [box.boxExtents]
ELSE {
bearoffExtents: TSTypes.Dimensions ~ BearoffExtents[table, box];
MakeExtentsValid[box];
SELECT box.rowAlignment
FROM
flushTop => {
extents[up] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]];
extents[down] ← TSTypes.zeroDimn;
};
flushBottom => {
extents[up] ← TSTypes.zeroDimn;
extents[down] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]];
};
center => {
extents[up] ← extents[down] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]].DivDimn[2];
};
topBaseline => {
baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box];
baseline: BaselineListRec ← baselineList.first^;
extents[up] ← baseline.y;
extents[down] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y];
};
bottomBaseline => {
baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box];
baseline: BaselineListRec ← NthElement[baselineList, -1]^;
extents[up] ← baseline.y;
extents[down] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y];
};
centerOnTopBaseline => {
baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box];
numberOfBaselines: INT ~ Length[baselineList];
baseline: BaselineListRec ← NthElement[baselineList, (numberOfBaselines+1)/2]^;
extents[up] ← baseline.y;
extents[down] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y];
};
centerOnBottomBaseline => {
baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box];
numberOfBaselines: INT ~ Length[baselineList];
baseline: BaselineListRec ← NthElement[baselineList, (numberOfBaselines/2)+1]^;
extents[up] ← baseline.y;
extents[down] ← box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y];
};
ENDCASE => ERROR UnimplementedCase;
IF box.alignOnChar
THEN {
baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box];
baseline: BaselineListRec ←
IF box.alignFirst
THEN baselineList.first^
ELSE NthElement[baselineList, -1]^;
extents[left] ← baseline.x;
extents[right] ← box.nodeExtents[left].AddDimn[box.nodeExtents[right]].SubDimn[baseline.x];
}
ELSE {
SELECT box.colAlignment
FROM
flushLeft => {
extents[left] ← TSTypes.zeroDimn;
extents[right] ← box.nodeExtents[left].AddDimn[box.nodeExtents[right]]; };
flushRight => {
extents[left] ← box.nodeExtents[left].AddDimn[box.nodeExtents[right]];
extents[right] ← TSTypes.zeroDimn; };
center => extents[left] ← extents[right] ← box.nodeExtents[left].AddDimn[box.nodeExtents[right]].DivDimn[2];
ENDCASE => ERROR UnimplementedCase;
};
box.xOffset ← extents[right].SubDimn[box.nodeExtents[right]];
box.yOffset ← extents[down].SubDimn[box.nodeExtents[down]];
extents[left] ← extents[left].AddDimn[bearoffExtents[left]];
extents[right] ← extents[right].AddDimn[bearoffExtents[right]];
extents[up] ← extents[up].AddDimn[bearoffExtents[up]];
extents[down] ← extents[down].AddDimn[bearoffExtents[down]];
box.boxExtents ← extents;
box.nodeExtentsValid ← TRUE;
};
};
BearoffExtents:
PROCEDURE [table: TableBase.RefTable, box: TableBase.RefTableBox]
RETURNS [extents: TSTypes.Dimensions] ~ {
extents ← box.bearoffExtents;
Should check table.rows and table.cols for those specifications
IF extents[left] = TSTypes.nilDimn THEN extents[left] ← table.bearoffExtents[left];
IF extents[right] = TSTypes.nilDimn THEN extents[right] ← table.bearoffExtents[right];
IF extents[up] = TSTypes.nilDimn THEN extents[up] ← table.bearoffExtents[up];
IF extents[down] = TSTypes.nilDimn THEN extents[down] ← table.bearoffExtents[down];
};
MakeExtentsValid:
PROC [box: TableBase.RefTableBox] ~ {
IF
NOT box.nodeExtentsValid
THEN {
box.tsObject ← CreateTypesetObject[box.node];
box.nodeExtents ← box.tsObject.layoutProc[box.tsObject];
box.nodeExtentsValid ← TRUE;
};
};
BaselineList: TYPE ~ REF BaselineListRec;
BaselineListRec:
TYPE ~
RECORD [
x, y: TSTypes.Dimn,
extent: TSTypes.Dimensions];
Reverse:
PROC [list:
LIST
OF BaselineList]
RETURNS [
LIST
OF BaselineList] ~
TRUSTED {
RETURN [LOOPHOLE[List.Reverse[LOOPHOLE[list]], LIST OF BaselineList]];
};
Length:
PROC [list:
LIST
OF BaselineList]
RETURNS [
INT] ~
TRUSTED {
RETURN [List.Length[LOOPHOLE[list]]];
};
NthElement:
PROC [list:
LIST
OF BaselineList, n:
INT]
RETURNS [BaselineList] ~
TRUSTED {
RETURN [LOOPHOLE[List.NthElement[LOOPHOLE[list], n], BaselineList]];
};
BaselineListFromTableBox:
PROCEDURE [box: TableBase.RefTableBox]
RETURNS [baselineList:
LIST
OF BaselineList] ~
TRUSTED {
BaselinesFromDownList:
PROCEDURE [tsBox: TSObject.Box]
RETURNS [baselineList:
LIST
OF BaselineList] ~
TRUSTED {
WITH b: tsBox
SELECT
FROM
list => {
source: TSObject.ListReader ~ b.items.CreateReader[];
x: TSTypes.Dimn ← TSTypes.zeroDimn;
y: TSTypes.Dimn ← TSTypes.zeroDimn;
UNTIL source.End[]
DO
SELECT source.CurrentTag[]
FROM
exception => {
item: REF ANY ← source.CurrentItem[];
SELECT
TRUE
FROM
ISTYPE[item, TSObject.Box] => {
tsBox: TSObject.Box ~ NARROW[item];
WITH b: tsBox
SELECT
FROM
list => {
baseline: BaselineListRec ← BaselineFromRightList[tsBox];
baseline.y ← baseline.y.AddDimn[y];
y ← y.AddDimn[baseline.extent[up]].AddDimn[baseline.extent[down]];
baselineList ← CONS[NEW[BaselineListRec ← baseline], baselineList];
};
ENDCASE => ERROR;
};
ISTYPE[item, TSObject.Glue] => {
glue: TSObject.Glue ~ NARROW[item];
delta: TSTypes.Dimn ~ TSGlue.FixGlue[glue^, b.glueset];
y ← y.AddDimn[delta];
};
ISTYPE[item, TSObject.Kern] => {
kern: TSObject.Kern ~ NARROW[item];
y ← y.AddDimn[kern^];
};
ENDCASE => ERROR;
};
ENDCASE => ERROR;
source.Next[];
ENDLOOP;
};
ENDCASE => ERROR ImplementationError["inside BaselinesFromDownList with a nonlist box"];
IF baselineList # NIL THEN baselineList ← Reverse[baselineList];
};
BaselineFromRightList:
PROCEDURE [tsBox: TSObject.Box]
RETURNS [BaselineListRec] ~
TRUSTED {
WITH b: tsBox
SELECT
FROM
list => {
x: TSTypes.Dimn ← TSTypes.zeroDimn;
y: TSTypes.Dimn ← TSTypes.zeroDimn;
x ← x.AddDimn[b.extent[left]];
y ← y.AddDimn[b.extent[up]];
IF box.alignOnChar
THEN
x ← x.AddDimn[PositionOfAlignChar[box.alignChar, box.alignFirst, b.items.CreateReader[], b.glueset]];
RETURN [[x, y, b.extent]];
};
ENDCASE => ERROR ImplementationError["inside BaselineFromRightList with a nonlist box"];
};
tsBox: TSObject.Box;
IF NOT box.nodeExtentsValid THEN MakeExtentsValid[box];
tsBox ← BoxFromTypesetObject[box.tsObject];
WITH b: tsBox
SELECT
FROM
list => {
SELECT b.direction
FROM
down => baselineList ← BaselinesFromDownList[tsBox];
right => baselineList ← LIST[NEW[BaselineListRec ← BaselineFromRightList[tsBox]]];
ENDCASE => ERROR UnimplementedCase;
};
ENDCASE => ERROR ImplementationError["Expecting a down list box from a TypsetObject"];
};
PositionOfAlignChar:
PROC [alignChar:
CHAR, alignFirst:
BOOLEAN, boxList: TSObject.ListReader, glueSet: TSGlue.GlueSet]
RETURNS [alignX: TSTypes.Dimn] ~ {
direction: TSObject.Direction ~ right;
opposite: TSObject.Direction ~ left;
x: TSTypes.Dimn ← TSTypes.zeroDimn;
lastCharX: TSTypes.Dimn ← TSTypes.zeroDimn;
UNTIL boxList.End[]
DO
SELECT boxList.CurrentTag[]
FROM
char => {
thisChar: CHAR ~ boxList.CurrentChar[];
extent: TSTypes.Dimensions ← boxList.currentFont.CharDimensions[thisChar];
IF alignChar = thisChar
THEN {
IF alignFirst THEN RETURN [lastCharX];
};
lastCharX ← x ← x.AddDimn[extent[direction].SubDimn[extent[opposite]]];
boxList.Next[];
};
space => {
WHILE boxList.CurrentTag[] = space
DO
x ← x.AddDimn[TSGlue.FixGlue[boxList.currentFont.SpaceGlue[], glueSet]];
boxList.Next[];
ENDLOOP;
};
exception => {
item: REF ANY ← boxList.CurrentItem[];
SELECT
TRUE
FROM
ISTYPE[item, TSObject.Glue] => {
g: TSObject.Glue ← NARROW[item];
x ← x.AddDimn[TSGlue.FixGlue[g^, glueSet]];
boxList.Next[];
};
ISTYPE[item, TSObject.Kern] => {
x ← x.AddDimn[NARROW[item, TSObject.Kern]^];
boxList.Next[];
};
ENDCASE => ERROR UnimplementedCase;
};
ENDCASE => ERROR UnimplementedCase;
ENDLOOP;
RETURN [lastCharX];
};
CreateTypesetObject: TSArtwork.ObjectFromBranchProc = {
object ← NEW[TSGraphic.ObjectRec];
object.paintProc ← TypesetObjectPaint;
object.layoutProc ← TypesetObjectLayout;
object.data ← NEW[TypesetObjectRec ← [node: node]];
};
TypesetObjectRec:
TYPE =
RECORD [
node: TextNode.Ref,
vlist: TSObject.ItemList,
box: TSObject.Box
];
TypesetObjectLayout: TSGraphic.LayoutProc =
TRUSTED {
data: REF TypesetObjectRec ← NARROW[self.data];
data.vlist ← TSTranslate.TreeToVlist[data.node].galley;
data.box ← TSOps.GetSlimBoxFrom[data.vlist];
extent ← data.box.extent;
};
TypesetObjectPaint: TSGraphic.PaintProc = {
data: REF TypesetObjectRec ← NARROW[self.data];
TSOutput.BoxOut[NARROW[context], originX, originY, data.box^];
};
BoxFromTypesetObject:
PROC [self: TSGraphic.Object]
RETURNS [box: TSObject.Box] ~ {
data: REF TypesetObjectRec ← NARROW[self.data];
box ← data.box;
};