TableLayoutImpl.Mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Rick Beach, February 18, 1985 10:07:47 pm PST
DIRECTORY
List,
TableBase,
TableConstraints,
TableLayout,
TextNode,
TSArtwork,
TSFont,
TSGlue,
TSGraphic,
TSObject,
TSOps,
TSOutput,
TSTranslate,
TSTypes;
TableLayoutImpl: CEDAR PROGRAM
IMPORTS List, TableBase, TableConstraints, TSFont, TSGlue, TSObject, TSOps, TSOutput, TSTranslate, TSTypes
EXPORTS TableLayout = {
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;
};
}.