<> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <<>> DIRECTORY Ascii, CD, CDCells, CDCellsExtras, CDDirectory, CDEvents, CDInstances, CDOpsExtras, CDPrivate, CDProperties, CDSatellites, CDTexts, CDTextsExtras, Rope; CDSatellitesImpl: CEDAR PROGRAM IMPORTS Ascii, CD, CDCells, CDCellsExtras, CDDirectory, CDEvents, CDInstances, CDOpsExtras, CDPrivate, CDProperties, CDTextsExtras, Rope EXPORTS CDSatellites = BEGIN OPEN CDSatellites; ROPE: TYPE = Rope.ROPE; satellitesProp: REF ATOM ~ NEW[ATOM_$CDSatellitesSatList]; <> <> <> <<>> maxGroupIdProp: ATOM ~ $CDSatellitesMax; <> <> <> iGroupIdProp: ATOM ~ $CDSatellitesGroupId; <> <> <> oGroupIdProp: ATOM ~ $CDSatellitesOGroup; <> <> <> noGroup: INT = -1; maxGroupId: INT _ noGroup+1; GetSatellites: PUBLIC PROC [from: REF] RETURNS [sats: CD.InstanceList_NIL] = { <<--external, does not assume but check invariants for objects and designs>> <<--assumes invariants for instances>> WITH from SELECT FROM d: CD.Design => RETURN [EnforceInvariants[CDOpsExtras.RealTopCell[d]]]; --not cached ob: CD.Object => IF CDCellsExtras.IsDummyCell[ob] THEN RETURN [EnforceInvariants[ob]]; ENDCASE => NULL; WITH CDProperties.GetProp[from, satellitesProp] SELECT FROM s: CD.InstanceList => RETURN [s]; a: ATOM => IF a=$none THEN RETURN [NIL]; ENDCASE => NULL; WITH from SELECT FROM ob: CD.Object => IF CDCells.IsCell[ob] THEN RETURN [EnforceInvariants[ob]]; i: CD.Instance => RETURN [NIL]; ENDCASE => ERROR; }; InternalGetSatellites: PROC [x: REF] RETURNS [CD.InstanceList] = INLINE { WITH CDProperties.GetProp[x, satellitesProp] SELECT FROM list: CD.InstanceList => RETURN [list]; ENDCASE => RETURN [NIL]; }; InternalPutSatellites: PROC [x: REF, sats: REF] = INLINE { WITH x SELECT FROM i: CD.Instance => CDProperties.PutInstanceProp[i, satellitesProp, sats]; ENDCASE => CDProperties.PutProp[x, satellitesProp, IF sats=NIL THEN $none ELSE sats]; }; EnforceInvariants: PROC [cell: CD.Object] RETURNS [oSats: CD.InstanceList_NIL] = { world: CD.InstanceList _ NARROW[cell.specificRef, CD.CellPtr].contents; Node: TYPE = REF NodeRec; NodeRec: TYPE = RECORD [ id: INT _ -1, list: CD.InstanceList _ NIL]; Table: TYPE = REF TableRec; TableRec: TYPE = RECORD [ elements: SEQUENCE size: NAT OF LIST OF Node ]; masterTable: Table _ NEW[TableRec[67]]; iSats: CD.InstanceList; oldObId: INT; newObId: REF _ NewId[]; Hash: PROC [i: INT] RETURNS [INT] = INLINE { RETURN[ABS[i] MOD masterTable.size] }; StoreMaster: PROC [inst: CD.Instance] = { id: INT _ IGroupId[inst]; hash: INT _ Hash[id]; FOR nl: LIST OF Node _ masterTable[hash], nl.rest WHILE nl#NIL DO IF nl.first.id=id THEN {nl.first.list _ CONS[inst, nl.first.list]; RETURN}; ENDLOOP; masterTable[hash] _ CONS[NEW[NodeRec _ [id: id, list: LIST[inst]]], masterTable[hash]]; }; FetchMaster: PROC [id: INT] RETURNS [CD.InstanceList] = { hash: INT _ Hash[id]; FOR nl: LIST OF Node _ masterTable[hash], nl.rest WHILE nl#NIL DO IF nl.first.id=id THEN RETURN [nl.first.list]; ENDLOOP; RETURN [NIL]; }; TrustedMakeInstSat: PROC [master: CD.Instance, satellite: CD.Instance] = { <> sats: CD.InstanceList _ NIL; WITH InternalGetSatellites[master] SELECT FROM sats: CD.InstanceList => { IF Member[sats, satellite] THEN ERROR; sats.rest _ CONS[satellite, sats.rest]; RETURN }; ENDCASE => sats _ LIST[satellite]; CDProperties.PutInstanceProp[master, satellitesProp, sats]; }; <> oldObId _ OGroupId[cell]; CDProperties.PutObjectProp[cell, oGroupIdProp, newObId]; <<>> <<--Make masterTable and iSats; at the same time strip masters of their satellite lists>> FOR w: CD.InstanceList _ world, w.rest WHILE w#NIL DO WITH w.first.ob.specificRef SELECT FROM tp: CDTexts.TextPtr => IF IGroupId[w.first]#noGroup THEN iSats _ CONS[w.first, iSats]; ENDCASE => IF IGroupId[w.first]#noGroup THEN { StoreMaster[w.first]; CDProperties.PutInstanceProp[w.first, satellitesProp, NIL]; } ENDLOOP; <<--For each satellite find its closest master and put it on that master's satellite list>> FOR sl: CD.InstanceList _ iSats, sl.rest WHILE sl#NIL DO Closer: PROC [newMaster: CD.Instance] RETURNS [BOOL] = INLINE { <> mRect, newMRect, sRect: CD.Rect; IF master=NIL THEN RETURN [TRUE]; mRect _ CDInstances.InstRectO[master]; newMRect _ CDInstances.InstRectO[newMaster]; sRect _ CDInstances.InstRectO[sl.first]; RETURN [RectMinDist[newMRect, sRect] < RectMinDist[mRect, sRect]]; }; master: CD.Instance _ NIL; satGId: INT _ IGroupId[sl.first]; FOR ml: CD.InstanceList _ FetchMaster[satGId], ml.rest WHILE ml#NIL DO IF satGId#IGroupId[ml.first] THEN ERROR; IF Closer[ml.first] THEN master _ ml.first; ENDLOOP; IF master#NIL THEN --InstSat-- TrustedMakeInstSat[master, sl.first] ELSE IF satGId=oldObId THEN --ObjectSat-- { CDProperties.PutInstanceProp[sl.first, iGroupIdProp, newObId]; oSats _ CONS[sl.first, oSats]; } ELSE --not a satellite-- CDProperties.PutInstanceProp[sl.first, iGroupIdProp, NIL] ENDLOOP; <> FOR i: INT IN [0..masterTable.size) DO FOR nl: LIST OF Node _ masterTable[i], nl.rest WHILE nl#NIL DO FOR ml: CD.InstanceList _ nl.first.list.rest, ml.rest WHILE ml#NIL DO id: REF _ NewId[]; CDProperties.PutInstanceProp[ml.first, iGroupIdProp, id]; FOR sl: CD.InstanceList _ InternalGetSatellites[ml.first], sl.rest WHILE sl#NIL DO CDProperties.PutInstanceProp[sl.first, iGroupIdProp, id]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; InternalPutSatellites[cell, oSats]; }; GetSatelliteRopes: PUBLIC PROC [from: REF, filter: PROC [CD.Instance] RETURNS [BOOL]] RETURNS [ropes: LIST OF ROPE _ NIL] = { FOR list: CD.InstanceList _ GetSatellites[from], list.rest WHILE list#NIL DO IF filter=NIL OR filter[list.first] THEN { rope: ROPE _ NARROW[list.first.ob.specificRef, CDTexts.TextPtr].text; ropes _ CONS[rope, ropes]; } ENDLOOP; }; StandardFilter: PUBLIC PROC [inst: CD.Instance] RETURNS [BOOL_FALSE] = { WITH inst.ob.specificRef SELECT FROM tp: CDTexts.TextPtr => IF CD.LayerTechnology[inst.ob.layer]=NIL THEN RETURN [NOT IsItalic[tp.cdFont.supposedName]]; ENDCASE => NULL; }; Associate: PUBLIC PROC [master: REF, text: CD.Instance] = { WITH master SELECT FROM d: CD.Design => master _ CDOpsExtras.RealTopCell[d]; ENDCASE => NULL; IF text=NIL THEN { WITH master SELECT FROM o: CD.Object => OPutGroup[o, NIL]; i: CD.Instance => IPutGroup[i, NIL]; ENDCASE => ERROR; } ELSE { id: REF _ NIL; IF ~CDTextsExtras.IsText[text.ob] THEN ERROR; WITH master SELECT FROM o: CD.Object => { id _ CDProperties.GetObjectProp[o, oGroupIdProp]; IF id=NIL THEN OPutGroup[o, id_NewId[]]; IPutGroup[text, id]; }; i: CD.Instance => IF ~CDTextsExtras.IsText[i.ob] THEN { id _ CDProperties.GetInstanceProp[i, iGroupIdProp]; IF id=NIL THEN IPutGroup[i, id_NewId[]]; IPutGroup[text, id]; } ELSE ERROR; ENDCASE => IF master#NIL THEN ERROR; IPutGroup[text, id]; }; }; IsAssociated: PUBLIC PROC [any: REF, inst: CD.Instance] RETURNS [BOOL] = { id: INT _ IGroupId[inst]; IF id=noGroup THEN RETURN [any=NIL]; RETURN [ WITH any SELECT FROM d: CD.Design => id=OGroupId[CDOpsExtras.RealTopCell[d]], o: CD.Object => id=OGroupId[o], i: CD.Instance => id=IGroupId[i], ENDCASE => FALSE ] }; GetMaster: PUBLIC PROC [cell: REF, text: CD.Instance] RETURNS [master: REF _ NIL] = { id: INT; world: CD.InstanceList _ NIL; IF ~CDTextsExtras.IsText[text.ob] THEN ERROR; [] _ GetSatellites[cell]; --enforces invariants id _ IGroupId[text]; IF id=noGroup THEN RETURN [NIL]; WITH cell SELECT FROM ob: CD.Object => { WITH ob.specificRef SELECT FROM cp: CD.CellPtr => world _ cp.contents; ENDCASE => ERROR; IF id=OGroupId[ob] THEN RETURN [ob]; }; d: CD.Design => { ob: CD.Object ~ CDOpsExtras.RealTopCell[d]; IF id=OGroupId[ob] THEN RETURN [d]; world _ NARROW[ob.specificRef, CD.CellPtr].contents; }; ENDCASE => NULL; FOR w: CD.InstanceList _ world, w.rest WHILE w#NIL DO IF id=IGroupId[w.first] AND ~CDTextsExtras.IsText[w.first.ob] THEN RETURN [w.first]; ENDLOOP; }; OPutGroup: PROC [ob: CD.Object, x: REF] = INLINE { CDProperties.PutObjectProp[ob, oGroupIdProp, x] }; IPutGroup: PROC [i: CD.Instance, x: REF] = INLINE { CDProperties.PutInstanceProp[i, iGroupIdProp, x] }; OGroupId: PROC [ob: CD.Object] RETURNS [INT] = { WITH CDProperties.GetObjectProp[ob, oGroupIdProp] SELECT FROM ri: REF INT => RETURN [ri^]; ENDCASE => RETURN [noGroup]; }; IGroupId: PROC [i: CD.Instance] RETURNS [INT_noGroup] = { WITH CDProperties.GetInstanceProp[i, iGroupIdProp] SELECT FROM ri: REF INT => RETURN [ri^]; ENDCASE => NULL; }; NewId: PROC [] RETURNS [REF] = { IF maxGroupId=LAST[INT] THEN maxGroupId _ noGroup+1; RETURN [NEW[INT _ maxGroupId _ maxGroupId+1]] }; BeforeOutput: CDEvents.EventProc = { IF design#NIL THEN CDProperties.PutProp[design, maxGroupIdProp, NEW[INT_maxGroupId]] }; AfterInput: CDEvents.EventProc = { [] _ CheckMaxGroupId[design]; }; Convert: PROC [design: CD.Design] = { ConvertCell: CDDirectory.EachEntryAction = { WITH ob.specificRef SELECT FROM cp: CD.CellPtr => { FOR l: CD.InstanceList _ cp.contents, l.rest WHILE l#NIL DO IF CDTextsExtras.IsText[l.first.ob] THEN IF CDProperties.GetProp[l.first, $CDSatellitesGroupId]=NIL THEN Associate[ob, l.first] ENDLOOP; }; ENDCASE => NULL; }; CDProperties.PutProp[design, $CDSatellitesMaxGroupId, NIL]; [] _ CDDirectory.Enumerate[design, ConvertCell]; FOR pl: LIST OF CD.PushRec _ design^.actual, pl.rest WHILE pl#NIL DO [] _ ConvertCell[NIL, pl.first.dummyCell.ob] ENDLOOP }; CheckMaxGroupId: PROC [design: CD.Design] RETURNS [BOOL_FALSE] = { MaxGroupId: PROC [design: CD.Design] RETURNS [n: INT _ -1] = { IF design#NIL THEN WITH CDProperties.GetProp[design, maxGroupIdProp] SELECT FROM i: REF INT => n _ i^; ENDCASE => NULL; }; IF design#NIL THEN { n: INT _ MaxGroupId[design]; IF n> <<--general utilities>> <<>> Member: PROC [instances: CD.InstanceList, inst: CD.Instance] RETURNS [BOOL _ FALSE] = { <> WHILE instances#NIL DO IF instances.first=inst THEN RETURN[TRUE]; instances _ instances.rest; ENDLOOP; }; RectMinDist: PROC [rectA, rectB: CD.Rect] RETURNS [INT] = INLINE { IntervalMinDist: PROC [i1min, i1max, i2min, i2max: INT] RETURNS [INT] = INLINE { IF i1maxi2max THEN RETURN [i1min-i2max]; RETURN [0]; }; xMinDist: INT ~ IntervalMinDist[rectA.x1, rectA.x2, rectB.x1, rectB.x2]; yMinDist: INT ~ IntervalMinDist[rectA.y1, rectA.y2, rectB.y1, rectB.y2]; RETURN [xMinDist+yMinDist] }; IsItalic: PROC [fontName: ROPE] RETURNS [BOOL_FALSE] = { pressFontLeng: INT = 17; pressFontName: ROPE = "Xerox/PressFonts/"; tiogaFontLeng: INT = 17; tiogaFontName: ROPE = "Xerox/TiogaFonts/"; leng: INT _ Rope.Length[fontName]; IF leng>tiogaFontLeng THEN IF Rope.Equal[Rope.Substr[fontName, 0, tiogaFontLeng], tiogaFontName, FALSE] THEN RETURN [Ascii.Upper[Rope.Fetch[fontName, leng-1]]='I]; IF leng>pressFontLeng THEN IF Rope.Equal[Rope.Substr[fontName, 0, pressFontLeng], pressFontName, FALSE] THEN RETURN [Ascii.Upper[Rope.Fetch[fontName, leng-2]]='I] }; [] _ CDProperties.RegisterProperty[satellitesProp, $CDSatellites]; [] _ CDProperties.RegisterProperty[maxGroupIdProp, $CDSatellites]; [] _ CDProperties.RegisterProperty[oGroupIdProp, $CDSatellites]; [] _ CDProperties.RegisterProperty[iGroupIdProp, $CDSatellites]; CDProperties.InstallProcs[satellitesProp, [makeCopy: CDProperties.CopyVal, autoRem: TRUE]]; CDProperties.InstallProcs[maxGroupIdProp, [makeCopy: CDProperties.CopyVal]]; CDProperties.InstallProcs[oGroupIdProp, [makeCopy: CDProperties.CopyVal, autoRem: FALSE]]; CDProperties.InstallProcs[iGroupIdProp, [makeCopy: CDProperties.CopyVal, autoRem: FALSE]]; CDEvents.RegisterEventProc[$BeforeOutput, BeforeOutput]; CDEvents.RegisterEventProc[$AfterInput, AfterInput]; [] _ CDPrivate.EnumDesigns[CheckMaxGroupId]; END.