<> <> <> 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] = { <> PaintTableBox: EnumeratedEntryProc = { <> 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 { <> 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; <> 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; }; }.