1 /*
2  * DBcell.c --
3  *
4  * Place and Delete subcells
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef	lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcell.c,v 1.2 2008/12/11 04:20:04 tim Exp $";
21 #endif	/* not lint */
22 
23 #include <sys/types.h>
24 #include <stdio.h>
25 
26 #include "utils/magic.h"
27 #include "utils/malloc.h"
28 #include "utils/geometry.h"
29 #include "tiles/tile.h"
30 #include "utils/hash.h"
31 #include "database/database.h"
32 #include "database/databaseInt.h"
33 #include "utils/undo.h"
34 #include "utils/signals.h"
35 
36 int placeCellFunc();
37 int deleteCellFunc();
38 Tile * clipCellTile();
39 void dupTileBody();
40 void cellTileMerge();
41 bool ctbListMatch();
42 void freeCTBList();
43 
44 struct searchArg
45 {
46     CellUse   * celluse;
47     Rect      * rect;
48     BPlane    * bplane;
49 };
50 
51 #define		TOPLEFT			10
52 #define		TOPLEFTRIGHT		11
53 #define		TOPBOTTOM		12
54 #define         TOPBOTTOMLEFT   	14
55 #define 	TOPBOTTOMLEFTRIGHT	15
56 
57 int dbCellDebug = 0;
58 
59 void
dbInstanceUnplace(CellUse * use)60 dbInstanceUnplace(CellUse *use)
61 {
62     ASSERT(use != (CellUse *) NULL, "dbInstanceUnplace");
63 
64     /* It's important that this code run with interrupts disabled,
65      * or else we could leave the subcell tile plane in a weird
66      * state.
67      */
68 
69     BPDelete(use->cu_parent->cd_cellPlane, use);
70 }
71 
72 
73 
74 /*
75  * ----------------------------------------------------------------------------
76  *
77  * DBCellFindDup --
78  *
79  * 	This procedure indicates whether a particular cell is already
80  *	present at a particular point in a particular parent.  It is
81  *	used to avoid placing duplicate copies of a cell on top of
82  *	each other.
83  *
84  * Results:
85  *	The return value is NULL if there is not already a CellUse in parent
86  *	that is identical to use (same bbox and def).  If there is a duplicate
87  *	already in parent, then the return value is a pointer to its CellUse.
88  *
89  * Side effects:
90  *	None.
91  *
92  * ----------------------------------------------------------------------------
93  */
94 
95 CellUse *
DBCellFindDup(use,parent)96 DBCellFindDup(use, parent)
97     CellUse *use;		/* Use that is about to be placed in parent.
98 				 * Is it a duplicate?
99 				 */
100     CellDef *parent;		/* Parent definiton:  does it already have
101 				 * something identical to use?
102 				 */
103 {
104     BPEnum bpe;
105     CellUse *dupUse;
106 
107     BPEnumInit(&bpe, parent->cd_cellPlane, &use->cu_bbox, BPE_EQUAL,
108 		"DBCellFindDup");
109     while (dupUse = BPEnumNext(&bpe))
110 	if (dupUse->cu_def == use->cu_def) break;
111 
112     BPEnumTerm(&bpe);
113     return dupUse;
114 }
115 
116 
117 /*
118  * ----------------------------------------------------------------------------
119  *
120  * DBPlaceCell --
121  * DBPlaceCellNoModify --
122  *
123  * Add a CellUse to the subcell tile plane of a CellDef.
124  * Assumes prior check that the new CellUse is not an exact duplicate
125  *     of one already in place.
126  *
127  * Results:
128  *	None.
129  *
130  * Side effects:
131  *	Modifies the subcell tile plane of the given CellDef.
132  *	Resets the plowing delta of the CellUse to 0.  Sets the
133  *	CellDef's parent pointer to point to the parent def.
134  *
135  * ----------------------------------------------------------------------------
136  */
137 
138 void
DBPlaceCell(use,def)139 DBPlaceCell (use, def)
140     CellUse   * use;	/* new celluse to add to subcell tile plane */
141     CellDef   * def;    /* parent cell's definition */
142 {
143     Rect             rect;    /* argument to DBSrCellPlaneArea(), placeCellFunc() */
144     BPlane          *bplane;  /* argument to DBSrCellPlaneArea(), placeCellFunc() */
145     struct searchArg arg;     /* argument to placeCellFunc() */
146 
147     ASSERT(use != (CellUse *) NULL, "DBPlaceCell");
148     ASSERT(def, "DBPlaceCell");
149 
150     /* To do:  Check non-duplicate placement, check non-duplicate ID */
151 
152     use->cu_parent = def;
153 
154     /* Be careful not to permit interrupts during this, or the
155      * database could be left in a trashed state.
156      */
157 
158     SigDisableInterrupts();
159     BPAdd(def->cd_cellPlane, use);
160     def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
161     if (UndoIsEnabled())
162 	DBUndoCellUse(use, UNDO_CELL_PLACE);
163     SigEnableInterrupts();
164 }
165 
166 /* Like DBPlaceCell(), but don't change the flags of the parent cell.	*/
167 /* This is needed by the bounding box recalculation routine, which may	*/
168 /* cause the cell to be deleted and replaced for the purpose of		*/
169 /* capturing the bounding box information in the BPlane structure, but	*/
170 /* this does not mean that anything in the parent cell has changed.	*/
171 
172 void
DBPlaceCellNoModify(use,def)173 DBPlaceCellNoModify (use, def)
174     CellUse   * use;	/* new celluse to add to subcell tile plane */
175     CellDef   * def;    /* parent cell's definition */
176 {
177     Rect             rect;    /* argument to DBSrCellPlaneArea(), placeCellFunc() */
178     BPlane          *bplane;  /* argument to DBSrCellPlaneArea(), placeCellFunc() */
179     struct searchArg arg;     /* argument to placeCellFunc() */
180 
181     ASSERT(use != (CellUse *) NULL, "DBPlaceCell");
182     ASSERT(def, "DBPlaceCell");
183 
184     /* To do:  Check non-duplicate placement, check non-duplicate ID */
185 
186     use->cu_parent = def;
187 
188     /* Be careful not to permit interrupts during this, or the
189      * database could be left in a trashed state.
190      */
191 
192     SigDisableInterrupts();
193     BPAdd(def->cd_cellPlane, use);
194     if (UndoIsEnabled())
195 	DBUndoCellUse(use, UNDO_CELL_PLACE);
196     SigEnableInterrupts();
197 }
198 
199 /*
200  * ----------------------------------------------------------------------------
201  * DBDeleteCell --
202  *
203  * Remove a CellUse from the subcell tile plane of a CellDef.
204  * If "nomodify" is TRUE, then don't set the parent cell's CDMODIFIED flag.
205  * This is needed when recomputing the bounding box, which should not by
206  * itself change the modified state.
207  *
208  * Results:
209  *	None.
210  *
211  * Side effects:
212  *	Modifies the subcell tile plane of the CellDef, sets the
213  * 	parent pointer of the deleted CellUse to NULL.
214  * ----------------------------------------------------------------------------
215  */
216 
217 void
DBDeleteCell(use)218 DBDeleteCell (use)
219     CellUse * use;
220 {
221     ASSERT(use != (CellUse *) NULL, "DBDeleteCell");
222 
223     /* It's important that this code run with interrupts disabled,
224      * or else we could leave the subcell tile plane in a weird
225      * state.
226      */
227 
228     SigDisableInterrupts();
229     dbInstanceUnplace(use);
230     use->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
231     if (UndoIsEnabled())
232 	DBUndoCellUse(use, UNDO_CELL_DELETE);
233     use->cu_parent = (CellDef *) NULL;
234     SigEnableInterrupts();
235 }
236 
237 /*
238  * ----------------------------------------------------------------------------
239  * DBDeleteCellNoModify --
240  *
241  * Remove a CellUse from the subcell tile plane of a CellDef, as above,
242  * but don't set the parent cell's CDMODIFIED flag.  This is needed when
243  * recomputing the bounding box, which should not by itself change the
244  * modified state.
245  *
246  * Results:
247  *	None.
248  *
249  * Side effects:
250  *	Modifies the subcell tile plane of the CellDef, sets the
251  * 	parent pointer of the deleted CellUse to NULL.
252  * ----------------------------------------------------------------------------
253  */
254 
255 void
DBDeleteCellNoModify(use)256 DBDeleteCellNoModify (use)
257     CellUse * use;
258 {
259     ASSERT(use != (CellUse *) NULL, "DBDeleteCell");
260 
261     /* It's important that this code run with interrupts disabled,
262      * or else we could leave the subcell tile plane in a weird
263      * state.
264      */
265 
266     SigDisableInterrupts();
267     dbInstanceUnplace(use);
268     if (UndoIsEnabled())
269 	DBUndoCellUse(use, UNDO_CELL_DELETE);
270     use->cu_parent = (CellDef *) NULL;
271     SigEnableInterrupts();
272 }
273