DIRECTORY CD, CDAbuts, CDBasics USING [Inside], CDCells USING [CreateEmptyCell], CDDirectory, CDEvents USING [EventProc, RegisterEventProc], CDObjectProcs USING [FetchFurther, RegisterFurther, StoreFurther], CDOrient USING [MapRect, Orientation], CDProperties USING [CopyVal, DontCopy, FetchProcs, GetPropFromObject, PutPropOnApplication, PutPropOnObject, RegisterProperty], Convert, PWBasics, PWLow, PWStretch, Rope, TerminalIO USING [UserSaysYes]; PWLowImpl: CEDAR PROGRAM IMPORTS CD, CDAbuts, CDBasics, CDCells, CDDirectory, CDEvents, CDObjectProcs, CDOrient, -- CDPinObjects, -- CDProperties, -- CDRects, CMos, -- Convert, PWBasics, PWStretch, Rope, TerminalIO EXPORTS PWLow = BEGIN OPEN PWLow; SortedSegments: TYPE = PWStretch.SortedSegments; SortedStretchSegments: TYPE = PWStretch.SortedStretchSegments; Segment: TYPE = PWStretch.Segment; PosRange: TYPE = PWStretch.PosRange; ROPE: TYPE = PWStretch.ROPE; Edges: TYPE = REF EdgesRec; EdgesRec: TYPE = RECORD [ left, right, bottom, top: SortedSegments -- describes all pins starting at lower-left (resp lr, ll, ul) corner sorted in ascending Y (resp Y, X, X). Info field contains a CD.ObPtr of class Pin. ]; HorVer: TYPE = REF HorVerRec; HorVerRec: TYPE = RECORD [ hor, ver: SortedStretchSegments -- list of all vertical (resp horizontal) stretch possible areas, that is X (resp. Y) ranges where it is possible to stretch in X (resp Y). Info field contains a Stretch. ]; MakeObjNonStretchable: PUBLIC PROC [obj: CD.ObPtr] = { CDProperties.PutPropOnObject[obj, $ParseStretchProc, NEW [PWStretch.ParseStretchProc _ PWStretch.HardObjParseStretch]]; }; ReName: PUBLIC PROC [design: CD.Design, obj: CD.ObPtr, instanceName: ROPE] RETURNS [cell: CD.ObPtr] = {appl: CD.ApplicationPtr; cell _ CDCells.CreateEmptyCell[]; appl _ PWBasics.IncludeApplication[cell: cell, subcell: obj]; CDProperties.PutPropOnApplication[appl, $InstanceName, instanceName]; PWBasics.RepositionCell[design, cell, instanceName]}; AbutProblem: SIGNAL [what: ROPE] = CODE; GetCellEdges: PROC [obj: CD.ObPtr] RETURNS [edges: Edges] = {edges _ NARROW [CDProperties.GetPropFromObject[obj, $PWEdges]]}; PutCellEdges: PROC [obj: CD.ObPtr, edges: Edges] = {IF edges=NIL THEN ERROR; CDProperties.PutPropOnObject[obj, $PWEdges, edges]}; GetCellHorVer: PROC [obj: CD.ObPtr] RETURNS [horVer: HorVer] = {horVer _ NARROW [CDProperties.GetPropFromObject[obj, $PWHorVer]]}; PutCellHorVer: PROC [obj: CD.ObPtr, horVer: HorVer] = {IF horVer=NIL THEN ERROR; CDProperties.PutPropOnObject[obj, $PWHorVer, horVer]}; ChangeOrientation: PUBLIC PROC [design: CD.Design, obj: CD.ObPtr, orientation: CDOrient.Orientation] RETURNS [cell: CD.ObPtr] = BEGIN appl: CD.ApplicationPtr; proc: PWBasics.MapRectProc = {RETURN [CDOrient.MapRect[rect, obj.size, orientation]]}; cell _ CDCells.CreateEmptyCell[]; appl _ PWBasics.IncludeApplication[cell: cell, subcell: obj, orientation: orientation]; PWBasics.RepositionCell[design, cell]; END; ThreeObjRef: TYPE = REF ThreeObjRec; ThreeObjRec: TYPE = RECORD [obj2, newObj1, newObj2: CD.ObPtr]; FetchCache: PROC [abutX: BOOL, listObj: LIST OF CD.ObPtr] RETURNS [found: BOOL, newObj: CD.ObPtr _ NIL] = {RETURN [FALSE, NIL]}; StoreCache: PROC [abutX: BOOL, listObj: LIST OF CD.ObPtr, newObj: CD.ObPtr] = {}; AbutListX: PUBLIC PROC [design: CD.Design, listObj: LIST OF CD.ObPtr] RETURNS [abutX: CD.ObPtr] = BEGIN abutX _ AbutListInternal[design, listObj, "X", CDAbuts.CreateNewAbutX, TRUE]; END; AbutListY: PUBLIC PROC [design: CD.Design, listObj: LIST OF CD.ObPtr] RETURNS [abutY: CD.ObPtr] = BEGIN abutY _ AbutListInternal[design, listObj, "Y", CDAbuts.CreateNewAbutY, FALSE]; END; AbutListInternal: PROC [design: CD.Design, listObj: LIST OF CD.ObPtr, abutTypeRope: ROPE, createNewAbut: CDAbuts.CreateAbutProc, abutX: BOOL] RETURNS [newObj: CD.ObPtr] = BEGIN CleanList: PROC [listObj: LIST OF CD.ObPtr] RETURNS [newListObj: LIST OF CD.ObPtr _ NIL] = BEGIN WHILE listObj#NIL DO IF listObj.first#NIL THEN newListObj _ CONS [listObj.first, newListObj]; listObj _ listObj.rest; ENDLOOP; newListObj _ Reverse[newListObj]; END; AllSameISizeAndNoPin: PROC [listObj: LIST OF CD.ObPtr, iSize: CD.Position] RETURNS [same: BOOL _ TRUE] = BEGIN WHILE listObj#NIL DO edges: Edges; IF (IF abutX THEN PWBasics.GetISize[listObj.first].y#iSize.y ELSE PWBasics.GetISize[listObj.first].x#iSize.x) THEN RETURN [FALSE]; edges _ ParseEdges[design, listObj.first]; IF edges.right#NIL OR edges.left#NIL OR edges.top#NIL OR edges.bottom#NIL THEN RETURN [FALSE]; listObj _ listObj.rest; ENDLOOP; END; Length: PROC [listObj: LIST OF CD.ObPtr] RETURNS [length: INT _ 0] = {WHILE listObj#NIL DO length _ length+1; listObj _ listObj.rest ENDLOOP}; Reverse: PROC [listObj: LIST OF CD.ObPtr] RETURNS [result: LIST OF CD.ObPtr _ NIL] = {WHILE listObj#NIL DO result _ CONS [listObj.first, result]; listObj _ listObj.rest ENDLOOP}; length: INT; iSize: CD.Position; listObj _ CleanList[listObj]; length _ Length[listObj]; IF length=0 THEN RETURN [NIL]; IF length=1 THEN RETURN [listObj.first]; iSize _ PWBasics.GetISize[listObj.first]; IF AllSameISizeAndNoPin[listObj, iSize] THEN { newObj _ createNewAbut[listObj]; PWBasics.Include[design, newObj]; RETURN; }; BEGIN found: BOOL; [found, newObj] _ FetchCache[abutX, listObj]; IF found THEN RETURN; END; BEGIN ENABLE AbutProblem => {Error[design, abutTypeRope, listObj, what]; GOTO Return}; leftPins: SortedSegmentsSequence _ NEW [SortedSegmentsSequenceRec[length]]; rightPins: SortedSegmentsSequence _ NEW [SortedSegmentsSequenceRec[length]]; sizes: ValueSequence _ NEW [ValueSequenceRec[length]]; stretches: SortedSegmentsSequence; newObjs: ObPtrSequence _ NEW [ObPtrSequenceRec[length]]; newListObj: LIST OF CD.ObPtr _ listObj; FOR nb: INT IN [0..length) DO edges: Edges _ ParseEdges[design, newListObj.first]; IF abutX THEN { leftPins[nb] _ edges.left; rightPins[nb] _ edges.right; sizes[nb] _ PWBasics.GetISize[newListObj.first].y; } ELSE { leftPins[nb] _ edges.bottom; rightPins[nb] _ edges.top; sizes[nb] _ PWBasics.GetISize[newListObj.first].x; }; newObjs[nb] _ newListObj.first; newListObj _ newListObj.rest; ENDLOOP; stretches _ MatchPins[leftPins, rightPins, sizes]; FOR nb: INT IN [0..length) DO newObjs[nb] _ IF abutX THEN DoStretch[design, newObjs[nb], NIL, stretches[nb]] ELSE DoStretch[design, newObjs[nb], stretches[nb], NIL]; ENDLOOP; FOR nb: INT IN [1..length) DO IF (IF abutX THEN PWBasics.GetISize[newObjs[0]].y#PWBasics.GetISize[newObjs[nb]].y ELSE PWBasics.GetISize[newObjs[0]].x#PWBasics.GetISize[newObjs[nb]].x) THEN SIGNAL AbutProblem["Different sizes for rectangles!"]; ENDLOOP; FOR nb: INT DECREASING IN [0..length) DO newListObj _ CONS [newObjs[nb], newListObj]; ENDLOOP; newObj _ createNewAbut[newListObj]; PWBasics.Include[design, newObj]; StoreCache[abutX, listObj, newObj]; EXITS Return => RETURN [NIL]; END; END; AbutX: PUBLIC PROC [design: CD.Design, obj1, obj2: CD.ObPtr] RETURNS [abutX: CD.ObPtr] = {abutX _ AbutListX[design, LIST [obj1, obj2]]}; AbutY: PUBLIC PROC [design: CD.Design, obj1, obj2: CD.ObPtr] RETURNS [abutY: CD.ObPtr] = {abutY _ AbutListY[design, LIST [obj1, obj2]]}; Error: PROC [design: CD.Design, abutTypeRope: ROPE, listObj: LIST OF CD.ObPtr, what: ROPE] = BEGIN PWBasics.Output["PW Error while abuting in ", abutTypeRope, " objects "]; WHILE listObj#NIL DO PWBasics.Output["'", PWBasics.NameFromObj[listObj.first], "' "]; listObj _ listObj.rest; ENDLOOP; PWBasics.Output["': ", what, "\n"]; IF TerminalIO.UserSaysYes[text: "Do you want to open an error window for StackWalking until the error?", label: "Open EventViewer?", default: TRUE] THEN ERROR; END; ObPtrSequence: TYPE = REF ObPtrSequenceRec; ObPtrSequenceRec: TYPE = RECORD [contents: SEQUENCE size: [0..9999] OF CD.ObPtr]; SortedSegmentsSequence: TYPE = REF SortedSegmentsSequenceRec; SortedSegmentsSequenceRec: TYPE = RECORD [contents: SEQUENCE size: [0..9999] OF SortedSegments]; PosRangeSequence: TYPE = REF PosRangeSequenceRec; PosRangeSequenceRec: TYPE = RECORD [contents: SEQUENCE size: [0..9999] OF PosRange]; ValueSequence: TYPE = REF ValueSequenceRec; ValueSequenceRec: TYPE = RECORD [contents: SEQUENCE size: [0..9999] OF INT]; MatchPins: PROC [leftPins, rightPins: SortedSegmentsSequence, sizes: ValueSequence] RETURNS [stretches: SortedSegmentsSequence] = BEGIN PosAfterStretch: PROC [pos: INT, number: INT] RETURNS [newPos: INT] = { s: SortedSegments _ stretches[number]; newPos _ pos; WHILE s#NIL DO IF s.first.pos.max > pos THEN ERROR; newPos _ newPos + PWStretch.GetStretchValue[s.first]; s _ s.rest ENDLOOP; }; Stretch: PROC [number: INT, value: INT, stretchBefore: INT] = { stretches[number] _ PWStretch.InsertStretchSegment[ [previousPins[number], stretchBefore], value, stretches[number]]; }; DebugOutput: PROC [] = { OutputSortedSegments: PROC [s: SortedSegments] = { PWBasics.Output["("]; WHILE s#NIL DO PWBasics.Output[Convert.RopeFromInt[s.first.pos.min], "", Convert.RopeFromInt[s.first.pos.max]]; WITH s.first.info SELECT FROM value: REF INT => PWBasics.Output["[", Convert.RopeFromInt[value^], "]"]; ENDCASE => {}; PWBasics.Output[" "]; s _ s.rest; ENDLOOP; PWBasics.Output[")"]; }; FOR nb: INT IN [0..size) DO PWBasics.Output["Nb: ", Convert.RopeFromInt[nb], " left: "]; OutputSortedSegments[leftPins[nb]]; PWBasics.Output[" right: "]; OutputSortedSegments[rightPins[nb]]; PWBasics.Output[" stretches: "]; OutputSortedSegments[stretches[nb]]; PWBasics.Output[" previousPins: ", Convert.RopeFromInt[previousPins[nb]], "\n"]; ENDLOOP; }; size: INT _ sizes.size; previousPins: ValueSequence _ NEW [ValueSequenceRec[size]]; IF leftPins.size#size OR rightPins.size#size THEN ERROR; stretches _ NEW [SortedSegmentsSequenceRec[size]]; FOR nb: INT IN [0..size) DO previousPins[nb] _ 0; stretches[nb] _ NIL; ENDLOOP; DO pos: INT _ LAST [INT]; number: INT; maxDelta: INT _ 0; FOR nb: INT IN (0..size) DO left, right: SortedSegments; thesePinsPos: INT; delta: INT; left _ leftPins[nb]; right _ rightPins[nb-1]; IF left#NIL OR right#NIL THEN { IF left=NIL OR right=NIL THEN SIGNAL AbutProblem["Number of pins differ"]; thesePinsPos _ MIN [ PosAfterStretch[left.first.pos.min, nb], PosAfterStretch[right.first.pos.min, nb-1]]; delta _ ABS [PosAfterStretch[left.first.pos.min, nb] - PosAfterStretch[right.first.pos.min, nb-1]]; IF thesePinsPos < pos THEN { number _ nb; pos _ thesePinsPos; maxDelta _ delta; }; IF thesePinsPos = pos AND delta>maxDelta THEN { number _ nb; maxDelta _ delta; }; }; ENDLOOP; IF pos=LAST [INT] THEN EXIT; -- no pins left BEGIN leftPin: Segment _ leftPins[number].first; rightPin: Segment _ rightPins[number-1].first; delta: INT _ PosAfterStretch[leftPin.pos.min, number] - PosAfterStretch[rightPin.pos.min, number-1]; IF leftPin.pos.max-leftPin.pos.min # rightPin.pos.max-rightPin.pos.min THEN SIGNAL AbutProblem["Widths of corresponding pins differ"]; -- EMM SELECT TRUE FROM delta<0 => Stretch[number, -delta, leftPin.pos.min]; delta>0 => Stretch[number-1, delta, rightPin.pos.min]; ENDCASE => { -- these lowest pins are at same level, let's forget them leftPins[number] _ leftPins[number].rest; rightPins[number-1] _ rightPins[number-1].rest; previousPins[number] _ leftPin.pos.max; previousPins[number-1] _ rightPin.pos.max; }; END; ENDLOOP; BEGIN pos: INT _ 0; -- pos will be the highest interest rect FOR nb: INT IN [0..size) DO pos _ MAX [pos, PosAfterStretch[sizes[nb], nb]]; ENDLOOP; FOR nb: INT IN [0..size) DO IF pos#PosAfterStretch[sizes[nb], nb] THEN Stretch[nb, pos - PosAfterStretch[sizes[nb], nb], sizes[nb]]; ENDLOOP; END; END; ParsePinsProc: TYPE = PROC [design: CD.Design, obj: CD.ObPtr] RETURNS [left, right, bottom, top: SortedSegments]; ParseEdges: PROC [design: CD.Design, obj: CD.ObPtr] RETURNS [edges: Edges] = BEGIN edges _ GetCellEdges[obj]; IF edges=NIL THEN BEGIN edges _ NEW [EdgesRec]; [edges.left, edges.right, edges.bottom, edges.top] _ ParsePins[design, obj]; PutCellEdges[obj, edges]; END; END; ParseHorVer: PROC [design: CD.Design, obj: CD.ObPtr] RETURNS [horVer: HorVer] = BEGIN horVer _ GetCellHorVer[obj]; IF horVer=NIL THEN BEGIN edges: Edges = ParseEdges[design, obj]; size: CD.Position = PWBasics.GetISize[obj]; horVer _ NEW [HorVerRec]; [horVer.hor, horVer.ver] _ PWStretch.ParseStretch[design, obj]; horVer.hor _ PWStretch.Intersect[horVer.hor, PWStretch.Complement[edges.bottom, [0, size.x]]]; horVer.hor _ PWStretch.Intersect[horVer.hor, PWStretch.Complement[edges.top, [0, size.x]]]; horVer.ver _ PWStretch.Intersect[horVer.ver, PWStretch.Complement[edges.right, [0, size.y]]]; horVer.ver _ PWStretch.Intersect[horVer.ver, PWStretch.Complement[edges.left, [0, size.y]]]; PutCellHorVer[obj, horVer]; END; END; ParsePins: ParsePinsProc -- [design: CD.Design, obj: CD.ObPtr] RETURNS [left: PWStretch.SortedSegments, right: PWStretch.SortedSegments, bottom: PWStretch.SortedSegments, top: PWStretch.SortedSegments] -- = BEGIN AllMarks: TYPE = REF AllMarksRec; AllMarksRec: TYPE = RECORD [left, right, bottom, top: SortedSegments]; allmarks: AllMarks _ NARROW [CDProperties.GetPropFromObject[obj, $ParsedPins]]; refProc: REF; IF allmarks#NIL THEN RETURN [allmarks.left, allmarks.right, allmarks.bottom, allmarks.top]; refProc _ CDProperties.GetPropFromObject[obj, $ParsePinsProc]; IF refProc=NIL THEN refProc _ CDObjectProcs.FetchFurther[obj.p, $ParsePinsProc]; WITH refProc SELECT FROM proc: REF ParsePinsProc => [left, right, bottom, top] _ proc[design, obj]; ENDCASE => left _ right _ bottom _ top _ NIL; CDProperties.PutPropOnObject[obj, $ParsedPins, NEW [AllMarksRec _ [left, right, bottom, top]]]; END; PinParsePins: ParsePinsProc = BEGIN left _ right _ LIST [PWStretch.MakeNewSegment[[0, obj.size.y], obj]]; top _ bottom _ LIST [PWStretch.MakeNewSegment[[0, obj.size.x], obj]]; END; CellParsePins: ParsePinsProc = BEGIN size: CD.Position _ PWBasics.GetISize[obj]; FOR appls: CD.ApplicationList _ NARROW [obj.specificRef, CD.CellPtr].contents, appls.rest WHILE appls # NIL DO appl: CD.ApplicationPtr _ appls.first; location: CD.Position _ PWBasics.GetLocation[appl, obj]; subSize: CD.Position _ PWBasics.GetISize[appl.ob]; subLeft, subRight, subBottom, subTop: SortedSegments; LoopAddPin: PROC [mark: Segment, pinRect: CD.Rect] = BEGIN InsertPin: PROC [list: SortedSegments, pos: PosRange] RETURNS [SortedSegments] = {RETURN [PWStretch.Insert[pos: pos, info: mark.info, list: list]]}; pinRect _ CDOrient.MapRect[pinRect, subSize, appl.orientation, location]; IF ~CDBasics.Inside[pinRect, [0, 0, size.x, size.y]] THEN ERROR; SELECT TRUE FROM pinRect.x1=0 AND pinRect.y1 left _ InsertPin[left, PWStretch.PosRangeYFromRect[pinRect]]; pinRect.x2=size.x AND pinRect.y1 right _ InsertPin[right, PWStretch.PosRangeYFromRect[pinRect]]; pinRect.y1=0 AND pinRect.x1 bottom _ InsertPin[bottom, PWStretch.PosRangeXFromRect[pinRect]]; pinRect.y2=size.y AND pinRect.x1 top _ InsertPin[top, PWStretch.PosRangeXFromRect[pinRect]]; ENDCASE => {} ; END; [subLeft, subRight, subBottom, subTop] _ ParsePins[design, appl.ob]; FOR pins: SortedSegments _ subLeft, pins.rest WHILE pins#NIL DO pin: Segment _ pins.first; LoopAddPin[pin, PWStretch.RectFromPosRangeY[pin.pos, 0]]; ENDLOOP; FOR pins: SortedSegments _ subRight, pins.rest WHILE pins#NIL DO pin: Segment _ pins.first; LoopAddPin[pin, PWStretch.RectFromPosRangeY[pin.pos, subSize.x]]; ENDLOOP; FOR pins: SortedSegments _ subBottom, pins.rest WHILE pins#NIL DO pin: Segment _ pins.first; LoopAddPin[pin, PWStretch.RectFromPosRangeX[pin.pos, 0]]; ENDLOOP; FOR pins: SortedSegments _ subTop, pins.rest WHILE pins#NIL DO pin: Segment _ pins.first; LoopAddPin[pin, PWStretch.RectFromPosRangeX[pin.pos, subSize.y]]; ENDLOOP; ENDLOOP; END; AbutXParseStretch: PWStretch.ParseStretchProc -- [design: CD.Design, obj: CD.ObPtr] RETURNS [hor: PWStretch.SortedSegments, ver: PWStretch.SortedSegments] -- = BEGIN subObjs: LIST OF CD.ObPtr _ CDAbuts.GetAbutSubObjects[obj]; pos: CD.Number _ 0; hor _ NIL; ver _ PWStretch.worldSortedSegments; WHILE subObjs#NIL DO horVer: HorVer _ ParseHorVer[design, subObjs.first]; hor _ PWStretch.Append[hor, horVer.hor, pos]; ver _ PWStretch.Intersect[ver, horVer.ver]; pos _ pos + PWBasics.GetISize[subObjs.first].x; subObjs _ subObjs.rest; ENDLOOP; END; AbutXParsePins: ParsePinsProc -- [obj: CD.ObPtr] RETURNS [left: PWLowImpl.SortedSegments, right: PWLowImpl.SortedSegments, bottom: PWLowImpl.SortedSegments, top: PWLowImpl.SortedSegments] -- = BEGIN subObjs: LIST OF CD.ObPtr _ CDAbuts.GetAbutSubObjects[obj]; pos: CD.Number _ 0; IF subObjs#NIL THEN left _ ParseEdges[design, subObjs.first].left; WHILE subObjs#NIL DO edges: Edges _ ParseEdges[design, subObjs.first]; bottom _ PWStretch.Append[bottom, edges.bottom, pos]; top _ PWStretch.Append[top, edges.top, pos]; right _ edges.right; pos _ pos + PWBasics.GetISize[subObjs.first].x; subObjs _ subObjs.rest; ENDLOOP; END; AbutYParseStretch: PWStretch.ParseStretchProc -- [design: CD.Design, obj: CD.ObPtr] RETURNS [hor: PWStretch.SortedSegments, ver: PWStretch.SortedSegments] -- = BEGIN subObjs: LIST OF CD.ObPtr _ CDAbuts.GetAbutSubObjects[obj]; pos: CD.Number _ 0; ver _ NIL; hor _ PWStretch.worldSortedSegments; WHILE subObjs#NIL DO horVer: HorVer _ ParseHorVer[design, subObjs.first]; ver _ PWStretch.Append[ver, horVer.ver, pos]; hor _ PWStretch.Intersect[hor, horVer.hor]; pos _ pos + PWBasics.GetISize[subObjs.first].y; subObjs _ subObjs.rest; ENDLOOP; END; AbutYParsePins: ParsePinsProc -- [design: CD.Design, obj: CD.ObPtr] RETURNS [left: PWLowImpl.SortedSegments, right: PWLowImpl.SortedSegments, bottom: PWLowImpl.SortedSegments, top: PWLowImpl.SortedSegments] -- = BEGIN subObjs: LIST OF CD.ObPtr _ CDAbuts.GetAbutSubObjects[obj]; pos: CD.Number _ 0; IF subObjs#NIL THEN bottom _ ParseEdges[design, subObjs.first].bottom; WHILE subObjs#NIL DO edges: Edges _ ParseEdges[design, subObjs.first]; left _ PWStretch.Append[left, edges.left, pos]; right _ PWStretch.Append[right, edges.right, pos]; top _ edges.top; pos _ pos + PWBasics.GetISize[subObjs.first].y; subObjs _ subObjs.rest; ENDLOOP; END; ShareAmongSortedSegments: PROC [wanted: Segment, possible: SortedSegments] RETURNS [stretches: SortedStretchSegments _ NIL, feasable: BOOL _ FALSE] = { sigmaSizes: CD.Number _ 0; value: CD.Number _ PWStretch.GetStretchValue[wanted]; possible _ PWStretch.IntersectPosSegs[wanted.pos, possible]; IF possible=NIL THEN RETURN [NIL, FALSE]; FOR list: SortedSegments _ possible, list.rest WHILE list#NIL DO sigmaSizes _ sigmaSizes + list.first.pos.max - list.first.pos.min + 1; ENDLOOP; FOR list: SortedSegments _ possible, list.rest WHILE list#NIL DO pos: PosRange _ list.first.pos; thisSize: CD.Number _ pos.max - pos.min + 1; thisValue: CD.Number _ value * thisSize / sigmaSizes; stretches _ PWStretch.InsertStretchSegment[pos, thisValue, stretches]; value _ value - thisValue; sigmaSizes _ sigmaSizes - thisSize; ENDLOOP; IF value#0 THEN ERROR; RETURN [stretches, TRUE]; }; DoStretch: PROC [design: CD.Design, obj: CD.ObPtr, hor, ver: SortedSegments] RETURNS [newObj: CD.ObPtr] = BEGIN ChooseWhereToStretch: PROC [wanted: SortedStretchSegments, possible: SortedSegments] RETURNS [allStretches: SortedStretchSegments _ NIL] = { WHILE wanted#NIL DO stretches: SortedStretchSegments; feasable: BOOL; [stretches, feasable] _ ShareAmongSortedSegments[wanted.first, possible]; IF ~feasable THEN SIGNAL AbutProblem[Rope.Cat[PWBasics.NameFromObj[obj], " needed to be stretched between [", Rope.Cat[Convert.RopeFromInt[wanted.first.pos.min], ", ", Convert.RopeFromInt[wanted.first.pos.max], "] but was unable to perform stretch"]]]; WHILE stretches#NIL DO allStretches _ PWStretch.InsertStretchSegment[stretches.first.pos, PWStretch.GetStretchValue[stretches.first], allStretches]; stretches _ stretches.rest ENDLOOP; wanted _ wanted.rest; ENDLOOP; }; errMsg: ROPE; horVer: HorVer; IF hor=NIL AND ver=NIL THEN RETURN [obj]; horVer_ ParseHorVer[design, obj]; hor _ ChooseWhereToStretch[hor, horVer.hor]; ver _ ChooseWhereToStretch[ver, horVer.ver]; [newObj, errMsg] _ PWStretch.DoStretch[design, obj, hor, ver]; IF errMsg#NIL THEN SIGNAL AbutProblem[Rope.Cat["Some object needing to be stretched could not stretch recursively: ", PWBasics.NameFromObj[obj], " ", errMsg]]; END; AbutsDoStretch: PWStretch.DoStretchProc -- [design: CD.Design, obj: CD.ObPtr, hor: PWStretch.SortedSegments, ver: PWStretch.SortedSegments] RETURNS [newObj: CD.ObPtr, errMsg: ROPE _ NIL] -- = { obj _ CDDirectory.Expand[obj, NIL, NIL]; PWBasics.Include[design, obj]; [newObj, errMsg] _ PWStretch.DoStretch[design, obj, hor, ver]; }; FlushCaches: PUBLIC PROC [design: CD.Design] = BEGIN FlushEdges: CDDirectory.EachEntryAction = BEGIN CDProperties.PutPropOnObject[ob, $PWEdges, NIL]; CDProperties.PutPropOnObject[ob, $PWHorVer, NIL]; CDProperties.PutPropOnObject[ob, $ParsedPins, NIL]; CDProperties.PutPropOnObject[ob, $PWPreviousAbutX, NIL]; CDProperties.PutPropOnObject[ob, $PWPreviousAbutY, NIL]; CDProperties.PutPropOnObject[ob, $ParsedStretch, NIL]; END; [] _ CDDirectory.Enumerate[design, FlushEdges]; END; FlushWhenEvent: CDEvents.EventProc -- [event: REF ANY, design: CD.Design, x: REF ANY] RETURNS [dont: BOOL _ FALSE] -- = { FlushCaches[design]; }; [] _ CDProperties.RegisterProperty[$PWEdges, $PW]; [] _ CDProperties.RegisterProperty[$PWHorVer, $PW]; [] _ CDProperties.RegisterProperty[$ParsedPins, $PW]; [] _ CDProperties.RegisterProperty[$ParsePinsProc, $PW]; [] _ CDProperties.RegisterProperty[$PWPreviousAbutX, $PW]; [] _ CDProperties.RegisterProperty[$PWPreviousAbutY, $PW]; CDProperties.FetchProcs[$PWEdges].makeCopy _ CDProperties.DontCopy; CDProperties.FetchProcs[$PWHorVer].makeCopy _ CDProperties.DontCopy; CDProperties.FetchProcs[$ParsedPins].makeCopy _ CDProperties.DontCopy; CDProperties.FetchProcs[$PWPreviousAbutX].makeCopy _ CDProperties.DontCopy; CDProperties.FetchProcs[$PWPreviousAbutY].makeCopy _ CDProperties.DontCopy; CDProperties.FetchProcs[$ParsePinsProc].makeCopy _ CDProperties.CopyVal; IF CDObjectProcs.FetchFurther[CD.FetchObjectProcs[$Cell], $ParsePinsProc]=NIL THEN CDObjectProcs.RegisterFurther[$ParsePinsProc]; IF CD.FetchObjectProcs[$Cell]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$Cell]; CDObjectProcs.StoreFurther[p, $ParsePinsProc, NEW [ParsePinsProc _ CellParsePins]]; END; IF CD.FetchObjectProcs[$PinOb0]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$PinOb0]; CDObjectProcs.StoreFurther[p, $ParsePinsProc, NEW [ParsePinsProc _ PinParsePins]]; END; IF CD.FetchObjectProcs[$AbutX]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$AbutX]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [PWStretch.ParseStretchProc _ AbutXParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [PWStretch.DoStretchProc _ AbutsDoStretch]]; CDObjectProcs.StoreFurther[p, $ParsePinsProc, NEW [ParsePinsProc _ AbutXParsePins]]; END; IF CD.FetchObjectProcs[$AbutY]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$AbutY]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [PWStretch.ParseStretchProc _ AbutYParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [PWStretch.DoStretchProc _ AbutsDoStretch]]; CDObjectProcs.StoreFurther[p, $ParsePinsProc, NEW [ParsePinsProc _ AbutYParsePins]]; END; CDEvents.RegisterEventProc[$AfterCellReplacement, FlushWhenEvent]; END. ~PWLowImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reversed. Created by Bertrand Serlet Last Edited by: McCreight, December 27, 1984 11:19:21 am PST Last Edited by: Serlet, May 3, 1985 7:23:59 pm PDT Last Edited by: Monier, February 21, 1985 11:51:35 pm PST CDPinObjects USING [CreatePinOb], CDRects USING [CreateRect], CMos USING [met, met2], Internal data types Currently, all our objects are either Atomic, or Abuts. -- All Abuts have $DoStretchProc, $ParseStretchProc and $ParsePinsProc attributes, and, like all other objects they have $PWEdges and $PWHorVer attributes, once parsed. The internal data structure, hanging on obj under the prop $PWEdges. -- Cells may be shared in Abuts, but Edges are not. Utilities Makes an object non-stretchable (All it does is put a property on that object telling that for ParseStretch, the answer to the message should be NIL) -- Dealing with edges properties The cache laid on Objects for quickly telling the result of an Abut of obj1 and obj2 is a list of triplets [obj2, newObj1, newObj2] put on the property-list of obj1 under the name $PWPreviousAbutX or $PWPreviousAbutY {list: LIST OF ThreeObjRef _ NARROW [CDProperties.GetPropFromObject[obj1, prop]]; WHILE list#NIL DO IF list.first.obj2=obj2 THEN RETURN [TRUE, list.first.newObj1, list.first.newObj2]; list _ list.rest ENDLOOP; RETURN [FALSE, NIL, NIL]}; {list: LIST OF ThreeObjRef _ NARROW [CDProperties.GetPropFromObject[obj1, prop]]; list _ CONS [NEW [ThreeObjRec _ [obj2, newObj1, newObj2]], list]; CDProperties.PutPropOnObject[obj1, prop, list]}; Abuts with n arguments listObj can include some elements which are NIL. So the new list newListObj does not. A hack especially for Louis. RevAppend: PROC [revhead, tail: LIST OF CD.ObPtr] RETURNS [LIST OF CD.ObPtr] = {WHILE revhead#NIL DO tail _ CONS [revhead.first, tail]; revhead _ revhead.rest ENDLOOP; RETURN [tail]}; CutInTwo: PROC [listObj: LIST OF CD.ObPtr, lengthHead: INT] RETURNS [head, tail: LIST OF CD.ObPtr _ NIL] = {WHILE lengthHead>0 DO head _ CONS [listObj.first, head]; listObj _ listObj.rest; lengthHead _ lengthHead - 1 ENDLOOP; head _ Reverse[head]; tail _ listObj}; Append: PROC [head, tail: LIST OF CD.ObPtr] RETURNS [LIST OF CD.ObPtr] = {RETURN [RevAppend[Reverse[head], tail]]}; We look in the cache just in case they would be there We detect here mismatch of interest rectangles We make a big list for abuting them Abuts with 2 arguments Abuts with 2 arguments PWBasics.Output["ATTENTION: Objects are added SOMEWHERE in the design\n"]; PWBasics.AddAnObject[design, obj1, [0, 0]]; PWBasics.AddAnObject[design, obj2, IF Rope.Equal[abutTypeRope,"X"] THEN [obj1.size.x, 0] ELSE [0, obj1.size.y]]; PWBasics.AddAnObject[design, VisualizeEdgesFromObj[design, obj1], [500, 0]]; PWBasics.AddAnObject[design, VisualizeEdgesFromObj[design, obj2], IF Rope.Equal[abutTypeRope,"X"] THEN [500+ obj1.size.x, 0] ELSE [500, obj1.size.y]]; leftPins and rightPins are the edges to be fusionned. The first element of leftPins is unused, as for the last element of rightPins. sizes are the sizes of the obj. Returns stretches, the places where stretch should occur. PWBasics.Output["After Stretch!\n"]; DebugOutput[]; PWBasics.Output["Entry of proc!\n"]; DebugOutput[]; find position of lowest pin, inducing the biggest delta we know that the matches takes place between leftPins[number-1] and rightPins[number] PWBasics.Output["forget them!\n"]; DebugOutput[]; We must now enlarge the cells so to match the interest rects -- Code for parsing cells -- The general Proc calling all the others Now we avoid pins This proc is embedded in the loop because it uses the variables defined in it such as appl and iRect For Debug VisualizeEdges: PROC [design: CD.Design, size: CD.Position, edges: Edges] RETURNS [obj: CD.ObPtr] = {obj _ CDCells.CreateEmptyCell[]; FOR list: SortedSegments _ edges.left, list.rest WHILE list#NIL DO [] _ PWBasics.IncludeApplication[obj, CDPinObjects.CreatePinOb[[2, list.first.pos.max-list.first.pos.min]], [0, list.first.pos.min]] ENDLOOP; FOR list: SortedSegments _ edges.right, list.rest WHILE list#NIL DO [] _ PWBasics.IncludeApplication[obj, CDPinObjects.CreatePinOb[[2, list.first.pos.max-list.first.pos.min]], [size.x-2, list.first.pos.min]] ENDLOOP; FOR list: SortedSegments _ edges.bottom, list.rest WHILE list#NIL DO [] _ PWBasics.IncludeApplication[obj, CDPinObjects.CreatePinOb[[list.first.pos.max-list.first.pos.min, 2]], [list.first.pos.min, 0]] ENDLOOP; FOR list: SortedSegments _ edges.top, list.rest WHILE list#NIL DO [] _ PWBasics.IncludeApplication[obj, CDPinObjects.CreatePinOb[[list.first.pos.max-list.first.pos.min, 2]], [list.first.pos.min, size.y-2]] ENDLOOP; FOR list: SortedStretchSegments _ edges.hor, list.rest WHILE list#NIL DO [] _ PWBasics.IncludeApplication[obj, CDRects.CreateRect[[list.first.pos.max-list.first.pos.min, size.y], CMos.met], [list.first.pos.min, 0]] ENDLOOP; FOR list: SortedStretchSegments _ edges.ver, list.rest WHILE list#NIL DO [] _ PWBasics.IncludeApplication[obj, CDRects.CreateRect[[size.x, list.first.pos.max-list.first.pos.min], CMos.met2], [0, list.first.pos.min]] ENDLOOP; PWBasics.RepositionCell[design, obj]; }; VisualizeEdgesFromObj: PROC [design: CD.Design, obj: CD.ObPtr] RETURNS [CD.ObPtr] = {RETURN [VisualizeEdges[design, PWBasics.GetISize[obj], ParseEdges[design, obj]]]}; -- Procs for stretching Abut cells themselves Wanted is a StretchSegment (i.e. a PosRange and some value telling how much the stretch should be). Possible is a list of Segemnts where it is possible to stretch. Possible may perhaps not intersect wanted.pos, in which case the feasable flag will be set to FALSE. Otherwise, this proc issues a list of segments which should be really stretched. For now, the algorithm is to share nearly proportionnally to the size of the stretchable segments which intersect. All intersections are now found We look how big PosRange we have We share them fairly (here's the heuristic) In case of truncation errors This proc allows the stretching to take place where it is possible to stretch. Is can be improved, for example by sharing the amount of stretch wanted in all the posrange where it is possible. For the moment, the first possible place is taken. -- Flushing caches -- Some internal caches are set, this is the way for resetting them, for example when you change cells PWBasics.Output["Flushing PW cache\n"]; -- Registration of our properties -- We register our new ObjectProcs properties if they are not already there We register new ObjectProcs properties for Cells We register new ObjectProcs properties for PinObjects -- We register ObjectProcs properties for AbutX -- We register ObjectProcs properties for AbutY We must flush the cache each time a cell is changing Κ"˜– "Cedar" stylešœ™Jšœ Οmœ1™Jšœ žœ˜"Jšœ žœ˜$Jšžœžœ žœ˜J˜Jšœ¨™¨J˜JšœD™DJ™3JšŸœžœžœ ˜šœ žœžœ˜Jšœ*Οc˜˜ΒJšœ˜—Jšœžœžœ ˜šœ žœžœ˜Jšœ$ ͺ˜ΞJ˜——šœ ™ J™•šΟnœž œžœ ˜6Jšœ5žœ?˜wJ˜—J˜J™š‘œžœžœ žœžœžœžœžœ ˜eJšœžœ˜Jšœ"˜"Jšœ>˜>JšœE˜EJšœ5˜5—J™JšŸ œžœžœžœ˜(—˜™ J™š‘ œžœžœžœ˜;Jšœ žœ2˜A—J˜š‘ œžœžœ˜2Jš œžœžœžœžœ˜Jšœ4˜4—J˜š‘ œžœžœžœ˜>Jšœ žœ3˜C—J˜š‘ œžœžœ˜5Jš œžœžœžœžœ˜Jšœ6˜6—J˜—š‘œžœžœ žœžœ+žœžœ ˜Jšž˜Jšœžœ˜šŸœ˜Jšœžœ2˜9—Jšœ"˜"JšœW˜WJšœ&˜&Jšžœ˜—J˜JšœΨ™ΨJšœ žœžœ ˜$Jšœ žœžœžœ˜>š‘ œžœ žœ žœžœžœžœ žœ žœ žœ˜iJ•StartOfExpansion[]šœžœžœžœ.™Qšžœžœžœ™Jšžœžœžœžœ+™TJšœ™Jšžœ™—Jšžœžœžœžœ™Jšžœžœžœ˜J™—š‘ œžœ žœ žœžœžœžœ ˜MJšœžœžœžœ.™QJšœžœžœ1™AJšœ0™0J˜——J˜™J™š‘ œžœžœ žœžœžœžœžœ žœ ˜aJšž˜JšœGžœ˜MJšžœ˜—J˜š‘ œžœžœ žœžœžœžœžœ žœ ˜aJšž˜JšœGžœ˜NJšžœ˜—J˜š‘œžœ žœžœžœžœžœ0žœžœ žœ ˜ͺJšž˜JšœU™Uš‘ œžœ žœžœžœžœžœžœžœ žœ˜[Jšž˜šžœ žœž˜Jšžœžœžœžœ˜HJšœ˜Jšžœ˜—Jšœ!˜!Jšžœ˜J˜—Jšœ™š‘œžœ žœžœžœžœ žœžœžœ˜iJšž˜šžœ žœž˜J˜ Jšžœžœžœ,žœ-žœžœžœ˜‚Jšœ*˜*Jšžœ žœžœ žœžœ žœžœžœžœžœžœ˜^Jšœ˜Jšžœ˜—Jšžœ˜—š‘œžœ žœžœžœžœ žœ˜DJš œžœ žœžœ+žœ˜I—J˜š‘œžœ žœžœžœžœ žœžœžœ žœ˜TJš œžœ žœžœ žœ1žœ˜]—š‘ œžœžœžœžœžœžœžœžœ ™NJš œžœ žœžœžœ/žœ™XJšžœ ™—š‘œžœ žœžœžœžœžœžœžœžœ žœ™jšœžœžœ™Jšœžœ0™;Jšœ™Jšžœ™—Jšœ&™&—š‘œžœžœžœžœžœžœžœžœ ™HJšœžœ#™*—J™Jšœžœ žœ ˜ Jšœ˜Jšœ˜Jšžœ žœžœžœ˜Jšžœ žœžœ˜(Jšœ)˜)šžœ&žœ˜.Jšœ ˜ Jšœ!˜!Jšžœ˜Jšœ˜—Jšœ5™5šž˜Jšœžœ˜ Jšœ-˜-Jšžœžœžœ˜Jšžœ˜—šž˜šžœ˜Jšœ-žœ ˜:—Jšœ#žœ%˜KJšœ$žœ%˜LJšœžœ˜6Jšœ"˜"Jšœžœ˜8Jšœ žœžœžœ˜'šžœžœžœ ž˜Jšœ4˜4šžœžœ˜Jšœ7˜7Jšœ2˜2Jšœžœ˜Jšœ7˜7Jšœ2˜2J˜—Jšœ˜Jšœ˜Jšžœ˜—Jšœ2˜2šžœžœžœ ž˜Jš œžœžœ žœžœ/žœ˜‡Jšžœ˜ —Jšœ.™.šžœžœžœ ž˜šžœžœžœBžœB˜™Jšžœžœ0˜;—Jšžœ˜—Jšœ#™#š žœžœž œžœ ž˜(Jšœ žœ˜,Jšžœ˜—Jšœ#˜#Jšœ!˜!Jšœ#˜#Jšžœ žœžœ˜Jšžœ˜—Jšžœ˜——J˜™J™š‘œžœžœ žœžœžœ žœ ˜YJšœžœžœ˜/—J˜š‘œžœžœ žœžœžœ žœ ˜XJšžœžœ˜/——J˜™J™š‘œžœ žœžœ žœžœžœžœ˜\Jšž˜JšœI˜Išžœ žœžœ˜JšœA˜AJšœ˜Jšžœ˜—Jšœ#˜#JšœJ™JJšœ+™+Jšœ#žœžœžœ™pJšœL™LJšœBžœžœžœ™–JšžœŒžœžœžœ˜ŸJšžœ˜—J˜Jšœή™ήJšŸ œžœžœ˜+Jš œžœžœ žœžœžœ˜QJšŸœžœžœ˜=Jš œžœžœ žœžœ˜`JšŸœžœžœ˜1Jš œžœžœ žœžœ ˜TJšŸ œžœžœ˜+Jš œžœžœ žœžœžœ˜Lš‘ œžœEžœ&˜Jšž˜š ‘œžœžœ žœžœ žœ˜GJšœ&˜&J˜ šžœžœž˜Jšžœžœžœ˜$JšœAžœ˜I—J˜—J˜š ‘œžœ žœ žœžœ˜?šœ3˜3Jšœ'˜'Jšœ˜—Jšœ3™3J˜—J˜š‘ œžœ˜š‘œžœ˜2J˜šžœžœž˜J˜ašžœžœž˜Jšœžœžœ;˜IJšžœ ˜—J˜J˜ Jšžœ˜—J˜J˜—šžœžœžœ ž˜J˜˜hJšžœ˜—Jšžœ˜—Jšžœ˜——J˜™J™Jš Πbn œžœžœ žœžœžœ,˜qJ˜J™*š ’ œžœ žœžœžœ˜LJšž˜Jšœ˜šžœžœž˜Jšž˜Jšœžœ ˜JšœL˜LJšœ˜Jšžœ˜—Jšžœ˜—š ’ œžœ žœžœžœ˜OJšž˜Jšœ˜šžœžœž˜Jšž˜Jšœ'˜'Jšœžœ#˜+Jšœ žœ ˜Jšœ?˜?Jšœ™Jšœ^˜^Jšœ[˜[Jšœ]˜]Jšœ\˜\Jšœ˜Jšžœ˜—Jšžœ˜—J˜–’ -- [obj: CD.ObPtr] RETURNS [left: PWStretch.SortedSegments, right: PWStretch.SortedSegments, bottom: PWStretch.SortedSegments, top: PWStretch.SortedSegments] -- šŸ œΠck΄œ˜ΟJšž˜Jšœ žœžœ ˜!J–Κ -- [left: PWLowImpl.SortedMarks, right: PWLowImpl.SortedMarks, bottom: PWLowImpl.SortedMarks, top: PWLowImpl.SortedMarks, hor: PWStretch.SortedStretchSegments, ver: PWStretch.SortedStretchSegments] -- šœ žœžœ,˜FJšœžœ4˜OJšœ žœ˜Jšžœ žœžœžœ@˜[Jšœ>˜>Jšžœ žœžœ=˜Pšžœ žœž˜JšœžœA˜JJšžœ"žœ˜-—Jšœ/žœ-˜_Jšžœ˜—J˜–[]šŸ œ˜Jšž˜Jšœžœ2˜EJšœžœ2˜EJšžœ˜—J˜šŸ œ˜Jšž˜Jšœžœ#˜+šžœžœžœžœ˜ZJšžœ žœž˜Jšœžœ˜&Jšœ žœ,˜8Jšœ žœ'˜2Jšœ5˜5Jšœd™dš‘ œžœžœ ˜5Jšž˜š‘ œžœ'žœ˜PJšœžœ<˜C—JšœI˜IJšžœ3žœžœ˜@šžœžœž˜šœ žœ˜*Jšœ=˜=—šœžœ˜/Jšœ?˜?—šœ žœ˜*JšœA˜A—šœžœ˜/Jšœ;˜;—Jšžœ ˜—Jšžœ˜—J˜JšœD˜Dšžœ+žœžœž˜?Jšœ˜Jšœ9˜9Jšžœ˜—šžœ,žœžœž˜@Jšœ˜JšœA˜AJšžœ˜—šžœ-žœžœž˜AJšœ˜Jšœ9˜9Jšžœ˜—šžœ*žœžœž˜>Jšœ˜JšœA˜AJšžœ˜—Jšžœ˜—Jšžœ˜—J˜–^ -- [obj: CD.ObPtr] RETURNS [hor: PWStretch.SortedSegments, ver: PWStretch.SortedSegments] -- šŸœ£pœ˜ŸJšž˜Jšœ žœžœžœ(˜;Jšœžœ ˜Jšœžœ˜ Jšœ$˜$šžœ žœž˜Jšœ4˜4Jšœ.˜.Jšœ+˜+Jšœ/˜/Jšœ˜Jšžœ˜—Jšžœ˜—J˜–² -- [obj: CD.ObPtr] RETURNS [left: PWLowImpl.SortedMarkSegments, right: PWLowImpl.SortedMarkSegments, bottom: PWLowImpl.SortedMarkSegments, top: PWLowImpl.SortedMarkSegments] -- šŸœ£‘œ˜ΑJšž˜Jšœ žœžœžœ(˜;Jšœžœ ˜Jšžœ žœžœ/˜Bšžœ žœž˜Jšœ1˜1Jšœ5˜5Jšœ,˜,Jšœ˜Jšœ/˜/Jšœ˜Jšžœ˜—Jšžœ˜—J˜–^ -- [obj: CD.ObPtr] RETURNS [hor: PWStretch.SortedSegments, ver: PWStretch.SortedSegments] -- šŸœ£pœ˜ŸJšž˜Jšœ žœžœžœ(˜;Jšœžœ ˜Jšœžœ˜ Jšœ$˜$šžœ žœž˜Jšœ4˜4Jšœ.˜.Jšœ+˜+Jšœ/˜/Jšœ˜Jšžœ˜—Jšžœ˜—J˜–² -- [obj: CD.ObPtr] RETURNS [left: PWLowImpl.SortedMarkSegments, right: PWLowImpl.SortedMarkSegments, bottom: PWLowImpl.SortedMarkSegments, top: PWLowImpl.SortedMarkSegments] -- šŸœ£΄œ˜ΤJšž˜Jšœ žœžœžœ(˜;Jšœžœ ˜Jšžœ žœžœ3˜Fšžœ žœž˜Jšœ1˜1Jšœ/˜/Jšœ2˜2Jšœ˜Jšœ/˜/Jšœ˜Jšžœ˜—Jšžœ˜——J˜šœ ™ J˜š ‘œžœ žœžœžœžœ ™cJšœ!™!šžœ.žœžœž™BJšœ…žœ™—šžœ/žœžœž™CJšœŒžœ™”—šžœ0žœžœž™DJšœ…žœ™—šžœ-žœžœž™AJšœŒžœ™”—šžœ4žœžœž™HJšœŽžœ™–—šžœ4žœžœž™HJšœžœ™——Jšœ%™%J™—J˜š ‘œžœ žœžœžœžœ ™SJšœžœL™S——J˜™-J™JšœΝ™Νš ‘œžœ-žœ%žœ žœžœ˜—Jšœ žœ ˜Jšœžœ,˜5Jšœ<˜˜>Jšžœ˜—Jšœ™Jšžœ žœžœ˜Jšžœ žœ˜J˜J˜—š ‘ œžœ žœžœ"žœ žœ ˜iJšž˜Jšœσ™σš‘œžœ;žœ(žœ˜Œšžœžœž˜Jšœ,žœ˜1JšœI˜IJšžœ žœžœδ˜όšžœ žœžœ˜Jšœ}˜}Jšœžœ˜$—Jšœ˜Jšžœ˜ —J˜—J˜Jšœžœ˜ Jšœ˜Jš žœžœžœžœžœžœ˜)Jšœ!˜!Jšœ,˜,Jšœ,˜,Jšœ>˜>Jšžœžœžœžœ†˜ŸJšžœ˜—J˜–— -- [design: CD.Design, obj: CD.ObPtr, hor: PWStretch.SortedSegments, ver: PWStretch.SortedSegments] RETURNS [newObj: CD.ObPtr, errMsg: ROPE _ NIL] -- šŸœ£–œ˜ΒJšœžœžœ˜(Jšœ˜Jšœ>˜>Jšœ˜——J˜™J™fš‘ œžœžœ žœ ˜.Jšž˜šŸ œ ˜*Jšž˜Jšœ+žœ˜0Jšœ,žœ˜1Jšœ.žœ˜3Jšœ3žœ˜8Jšœ3žœ˜8Jšœ1žœ˜6Jšžœ˜—J™'Jšœ0˜0Jšžœ˜—J˜–T -- [event: REF ANY, design: CD.Design, x: REF ANY] RETURNS [dont: BOOL _ FALSE] -- šŸœ£Sœ˜zJšœ˜J˜——J™J™!Jšœ2˜2Jšœ3˜3Jšœ5˜5Jšœ8˜8Jšœ:˜:Jšœ:˜:J˜JšœC˜CJšœD˜DJšœF˜FJšœK˜KJšœK˜KJšœH˜HJ™J™Kšžœžœ*žœž˜RJšœ.˜.—J˜Jšœ1™1šžœžœžœž˜&Jšž˜Jšœžœžœžœ˜3Jšœ.žœ"˜SJšžœ˜—J˜Jšœ6™6šžœžœžœž˜(Jšž˜Jšœžœžœžœ˜5Jšœ.žœ!˜RJšžœ˜—J˜Jšžœžœžœž˜'šœ0™0Jšž˜Jšœžœžœžœ˜4Jšœ1žœ3˜gJšœ.žœ-˜^Jšœ.žœ#˜TJšžœ˜—J™Jšœ0™0šžœžœžœž˜'Jšž˜Jšœžœžœžœ˜4Jšœ1žœ3˜gJšœ.žœ-˜^Jšœ.žœ#˜TJšžœ˜—J˜Jšœ4™4JšœB˜BJ˜Jšžœ˜——…—Zτ—