1 /* CIFgen.c -
2  *
3  *	This file provides routines that generate CIF from Magic
4  *	tile information, using one of the styles read from the
5  *	technology file.
6  *
7  *     *********************************************************************
8  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
9  *     * Permission to use, copy, modify, and distribute this              *
10  *     * software and its documentation for any purpose and without        *
11  *     * fee is hereby granted, provided that the above copyright          *
12  *     * notice appear in all copies.  The University of California        *
13  *     * makes no representations about the suitability of this            *
14  *     * software for any purpose.  It is provided "as is" without         *
15  *     * express or implied warranty.  Export of this software outside     *
16  *     * of the United States of America may require an export license.    *
17  *     *********************************************************************
18  */
19 
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFgen.c,v 1.23 2010/06/24 20:35:54 tim Exp $";
22 #endif  /* not lint */
23 
24 #include <stdio.h>
25 #include <stdlib.h>             /* for abs() */
26 #include <math.h>		/* for ceil() and sqrt() */
27 
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "database/database.h"
33 #include "cif/CIFint.h"
34 #include "calma/calma.h"	/* for CalmaContactArrays */
35 #include "commands/commands.h"	/* for CmdFindNetProc()	*/
36 #include "select/selInt.h"	/* for select use and def */
37 #include "select/select.h"
38 #include "utils/stack.h"
39 #include "utils/malloc.h"
40 #include "utils/maxrect.h"
41 
42 /* TRUE to run (very slow) algorithm for optimizing non-manhattan tiles */
43 /* (cuts size of output;  see also the GDS "merge" option)		*/
44 bool CIFUnfracture = FALSE;
45 
46 /* The following global arrays hold pointers to the CIF planes
47  * generated by the procedures in this module.  There are two
48  * kinds of planes:  real CIF, which will ostensibly be output,
49  * and temporary layers used to build up more complex geometric
50  * functions.
51  */
52 
53 global Plane *CIFPlanes[MAXCIFLAYERS];
54 
55 /* The following are paint tables used by the routines that implement
56  * the geometric operations on mask layers, such as AND, OR, GROW,
57  * etc.  There are really only two tables.  The first will paint
58  * CIF_SOLIDTYPE over anything else, and the second will paint
59  * space over anything else.  These tables are used on planes with
60  * only two tile types, TT_SPACE and CIF_SOLIDTYPE, so they only
61  * have two entries each.
62  */
63 
64 PaintResultType CIFPaintTable[] = {CIF_SOLIDTYPE, CIF_SOLIDTYPE};
65 PaintResultType CIFEraseTable[] = {TT_SPACE, TT_SPACE};
66 
67 /* The following local variables are used as a convenience to pass
68  * information between CIFGen and the various search functions.
69  */
70 
71 static int growDistance;	/* Distance to grow stuff. */
72 static Plane *cifPlane;		/* Plane acted on by search functions. */
73 static int cifScale;		/* Scale factor to use on tiles. */
74 
75 extern void cifClipPlane();
76 extern void cifGenClip();
77 
78 /*
79  * ----------------------------------------------------------------------------
80  *
81  * cifPaintFunc --
82  *
83  * 	This search function is called during CIF_AND and CIF_OR
84  *	and CIF_ANDNOT operations for each relevant tile.
85  *
86  * Results:
87  *	Always returns 0 to keep the search alive.
88  *
89  * Side effects:
90  *	For the area of the tile, either paints or erases in
91  *	cifNewPlane, depending on the paint table passed as parameter.
92  *	The tile's area is scaled by cifScale first.
93  * ----------------------------------------------------------------------------
94  */
95 
96 int
cifPaintFunc(tile,table)97 cifPaintFunc(tile, table)
98     Tile *tile;
99     PaintResultType *table;		/* Used for painting. */
100 {
101     Rect area;
102 
103     TiToRect(tile, &area);
104     area.r_xbot *= cifScale;
105     area.r_xtop *= cifScale;
106     area.r_ybot *= cifScale;
107     area.r_ytop *= cifScale;
108 
109     DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &area, table,
110 		(PaintUndoInfo *) NULL);
111     CIFTileOps += 1;
112     return 0;
113 }
114 
115 /*
116  * ----------------------------------------------------------------------------
117  * SetBoxGrid ---
118  *
119  *	Adjust the given area by expanding each side individually to
120  *	ensure that it falls on the CIF minimum grid.
121  *
122  *  Returns:  Nothing
123  *
124  *  Side Effects:  Point to Rect "area" may be modified.
125  *
126  * ----------------------------------------------------------------------------
127  */
128 
129 void
SetBoxGrid(area)130 SetBoxGrid(area)
131     Rect *area;
132 {
133     int limit;
134     int delta;
135 
136     limit = CIFCurStyle->cs_gridLimit;
137 
138     if (CIFCurStyle && (limit > 1))
139     {
140 	delta = abs(area->r_xbot) % limit;
141 	if (delta > 0)
142 	{
143 	    if (area->r_xbot < 0)
144 	    {
145 		area->r_xbot += delta;
146 		area->r_xbot -= limit;
147 	    }
148 	    else
149 		area->r_xbot -= delta;
150 	}
151 
152 	delta = abs(area->r_xtop) % limit;
153 	if (delta > 0)
154 	{
155 	    if (area->r_xtop < 0)
156 		area->r_xtop += delta;
157 	    else
158 	    {
159 		area->r_xtop -= delta;
160 		area->r_xtop += limit;
161 	    }
162 	}
163 
164 	delta = abs(area->r_ybot) % limit;
165 	if (delta > 0)
166 	{
167 	    if (area->r_ybot < 0)
168 	    {
169 		area->r_ybot += delta;
170 		area->r_ybot -= limit;
171 	    }
172 	    else
173 		area->r_ybot -= delta;
174 	}
175 
176 	delta = abs(area->r_ytop) % limit;
177 	if (delta > 0)
178 	{
179 	    if (area->r_ytop < 0)
180 		area->r_ytop += delta;
181 	    else
182 	    {
183 		area->r_ytop -= delta;
184 		area->r_ytop += limit;
185 	    }
186 	}
187     }
188 }
189 
190 /*
191  * ----------------------------------------------------------------------------
192  * SetValueGrid ---
193  *
194  *	Adjust the given distance to the nearest CIF minimum grid.
195  *
196  *  Returns:  The adjusted value.
197  *
198  *  Side Effects:  None.
199  *
200  *  Notes:  Value is assumed to be a distance, therefore always positive.
201  *
202  * ----------------------------------------------------------------------------
203  */
204 
205 int
SetValueGrid(value)206 SetValueGrid(value)
207     int value;
208 {
209     int limit;
210     int delta;
211 
212     limit = CIFCurStyle->cs_gridLimit;
213 
214     if (CIFCurStyle && (limit > 1))
215     {
216 	delta = value % limit;
217 	if (delta > 0)
218 	    value += limit - delta;
219     }
220     return value;
221 }
222 
223 /*
224  * ----------------------------------------------------------------------------
225  * SetMinBoxGrid ---
226  *
227  *	Adjust the given area by expanding evenly on both sides so that it
228  *	has a width and heigth no less than the given width.  Then further
229  *	expand the box to ensure that it falls on the CIF minimum grid.
230  *
231  *  Returns:  Nothing
232  *
233  *  Side Effects:  Point to Rect "area" may be modified.
234  *
235  * ----------------------------------------------------------------------------
236  */
237 
238 void
SetMinBoxGrid(area,width)239 SetMinBoxGrid(area, width)
240     Rect *area;
241     int width;
242 {
243     int wtest;
244     int wtot;
245 
246     wtest = (area->r_xtop - area->r_xbot);
247     wtot = area->r_xtop + area->r_xbot;
248     if (wtest < width)
249     {
250 	area->r_xbot = (wtot - width) / 2;
251 	area->r_xtop = (wtot + width) / 2;
252     }
253     wtest = (area->r_ytop - area->r_ybot);
254     wtot = area->r_ytop + area->r_ybot;
255     if (wtest < width)
256     {
257 	area->r_ybot = (wtot - width) / 2;
258 	area->r_ytop = (wtot + width) / 2;
259     }
260 
261     SetBoxGrid(area);
262 }
263 
264 /*
265  * ----------------------------------------------------------------------------
266  *
267  * cifGrowMinFunc --
268  *
269  * 	Called for each relevant tile during grow-min operations.
270  *
271  * Results:
272  *	Always returns 0 to keep the search alive.
273  *
274  * Side effects:
275  *	May paint into cifNewPlane
276  *
277  * Algorithm (based on maximum horizontal stripes rule):
278  *	Scan top and bottom boundaries from left to right.  For any
279  *	distance (including distance zero) sharing the same type (0 or 1)
280  *	on both the tile top and bottom, find the diagonal length.  If
281  *	less than co_distance, then expand this area and paint.
282  *	NOTE:  This algorithm does not cover a number of geometry cases
283  *	and needs to be reworked.  It should be restricted to cases of
284  *	layers that have "rect_only" DRC rules.  Since the rule is usually
285  *	needed for implants on FET gates to maintain the implant width for
286  *	small gates, the "rect_only" requirement is not particularly
287  *	constraining.
288  *
289  * ----------------------------------------------------------------------------
290  */
291 
292 int
cifGrowMinFunc(tile,table)293 cifGrowMinFunc(tile, table)
294     Tile *tile;
295     PaintResultType *table;		/* Table to be used for painting. */
296 {
297     Rect area, parea;
298     int locDist, width, height, h;
299     TileType type, tptype;
300     Tile *tp, *tp2;
301     bool changed;
302     void SetMinBoxGrid();		/* Forward reference */
303 
304     TiToRect(tile, &area);
305 
306     area.r_xbot *= cifScale;
307     area.r_xtop *= cifScale;
308     area.r_ybot *= cifScale;
309     area.r_ytop *= cifScale;
310 
311     parea = area;
312     changed = FALSE;
313 
314     /* Check whole tile for minimum width */
315     width = area.r_xtop - area.r_xbot;
316     if (width < growDistance)
317     {
318 	locDist = (growDistance - width) / 2;
319 	area.r_xbot -= locDist;
320 	area.r_xtop += locDist;
321 
322 	/* If there is another tile on top or bottom, and the height is	*/
323 	/* less than minimum, then extend height in the direction of	*/
324 	/* the bordering tile.  Otherwise, if the height is less than	*/
325 	/* minimum, then grow halfway in both directions.		*/
326 
327 	height = area.r_ytop - area.r_ybot;
328 	if (height < growDistance)
329 	{
330 	    bool freeTop, freeBot;
331 
332 	    freeTop = freeBot = TRUE;
333 
334 	    for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
335 		if (TiGetTopType(tp) == TiGetBottomType(tile))
336 		{
337 		    freeBot = FALSE;
338 		    break;
339 		}
340 
341 	    for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
342 		if (TiGetBottomType(tp2) == TiGetTopType(tile))
343 		{
344 		    freeTop = FALSE;
345 		    break;
346 		}
347 
348 	    /* In the following, value h ensures that the euclidean */
349 	    /* distance between inside corners of the layer	    */
350 	    /* satisfies growDistance.				    */
351 
352 	    if (freeTop == TRUE && freeBot == FALSE)
353 	    {
354 		locDist = (growDistance - height) / 2;
355 		h = (int)sqrt((double)(growDistance * growDistance) -
356 			    0.25 * (double)((growDistance + width) *
357 			    (growDistance + width)) + 0.5);
358 		area.r_ybot -= h;
359 		changed = TRUE;
360 	    }
361 	    else if (freeTop == FALSE && freeBot == TRUE)
362 	    {
363 		h = (int)sqrt((double)(growDistance * growDistance) -
364 			    0.25 * (double)((growDistance + width) *
365 			    (growDistance + width)) + 0.5);
366 		area.r_ytop += h;
367 		changed = TRUE;
368 	    }
369 	    else {
370 		locDist = (growDistance - height) / 2;
371 		area.r_ybot -= locDist;
372 		area.r_ytop += locDist;
373 		changed = TRUE;
374 	    }
375 	}
376     }
377 
378     /* Ensure grid limit is not violated */
379     if (changed) SetMinBoxGrid(&area, growDistance);
380 
381     DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
382 
383     area = parea;
384 
385     /* Scan bottom from left to right */
386     for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
387     {
388 	tptype = TiGetTopType(tp);
389 	/* Scan top from right to left across range of tp */
390 	for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
391 	    if (TiGetBottomType(tp2) == tptype)
392 	    {
393 		/* Set range to length of overlap */
394 		if ((LEFT(tp2) <= RIGHT(tp)) && (LEFT(tp2) >= LEFT(tp)))
395 		{
396 		    area.r_xbot = LEFT(tp2) < LEFT(tile) ? LEFT(tile) : LEFT(tp2);
397 		    area.r_xtop = RIGHT(tp) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp);
398 		}
399 		else if ((RIGHT(tp2) >= LEFT(tp)) && (RIGHT(tp2) <= RIGHT(tp)))
400 		{
401 		    area.r_xbot = LEFT(tp) < LEFT(tile) ? LEFT(tile) : LEFT(tp);
402 		    area.r_xtop = RIGHT(tp2) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp2);
403 		}
404 		else continue;
405 
406 		area.r_xbot *= cifScale;
407 		area.r_xtop *= cifScale;
408 
409 		/* Does area violate minimum width requirement? */
410 		width = area.r_xtop - area.r_xbot;
411 		height = area.r_ytop - area.r_ybot;
412 
413 		/* Manhattan requirement (to-do: Euclidean) */
414 		if (width < growDistance)
415 		{
416 		    locDist = (growDistance - width) / 2;
417 		    parea.r_xbot = area.r_xbot - locDist;
418 		    parea.r_xtop = area.r_xtop + locDist;
419 		}
420 		else
421 		{
422 		    parea.r_xbot = area.r_xbot;
423 		    parea.r_xtop = area.r_xtop;
424 		}
425 		if (height < growDistance)
426 		{
427 		    locDist = (growDistance - height) / 2;
428 		    parea.r_ybot = area.r_ybot - locDist;
429 		    parea.r_ytop = area.r_ytop + locDist;
430 		}
431 		else
432 		{
433 		    parea.r_ybot = area.r_ybot;
434 		    parea.r_ytop = area.r_ytop;
435 		}
436 		if ((width < growDistance) || (height < growDistance))
437 		{
438     		    /* Ensure grid limit is not violated */
439 		    SetMinBoxGrid(&parea, growDistance);
440 		    DBPaintPlane(cifPlane, &parea, table, (PaintUndoInfo *) NULL);
441 		}
442 	    }
443     }
444 
445     CIFTileOps += 1;
446     return 0;
447 }
448 
449 /*
450  * ----------------------------------------------------------------------------
451  *
452  * cifGrowGridFunc --
453  *
454  * 	Called for each relevant tile during grow-grid operations.
455  *
456  * Results:
457  *	Always returns 0 to keep the search alive.
458  *
459  * Side effects:
460  *	Scales the tile by cifScale, then expands its area by the
461  *	remainder of the distance to the nearest grid point, as
462  *	defined by the grid distance (growDistance) in the current
463  *	CIFOp, then paints this area into cifNewPlane using the table
464  *	passed as parameter.
465  * ----------------------------------------------------------------------------
466  */
467 
468 int
cifGrowGridFunc(tile,table)469 cifGrowGridFunc(tile, table)
470     Tile *tile;
471     PaintResultType *table;		/* Table to be used for painting. */
472 {
473     Rect area;
474     int remainder;
475 
476     /* To be done---handle non-Manhattan geometry */
477     TileType oldType = TiGetType(tile);
478 
479     TiToRect(tile, &area);
480 
481     /* In scaling the tile, watch out for infinities!!  If something
482      * is already infinity, don't change it. */
483 
484     if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot *= cifScale;
485     if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot *= cifScale;
486     if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop *= cifScale;
487     if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop *= cifScale;
488 
489     /* In scaling the tile, watch out for infinities!!  If something
490      * is already infinity, don't change it. */
491 
492     if (area.r_xbot > TiPlaneRect.r_xbot)
493 	area.r_xbot -= (abs(area.r_xbot) % growDistance);
494     if (area.r_ybot > TiPlaneRect.r_ybot)
495 	area.r_ybot -= (abs(area.r_ybot) % growDistance);
496     if (area.r_xtop < TiPlaneRect.r_xtop)
497 	area.r_xtop += (abs(area.r_xtop) % growDistance);
498     if (area.r_ytop < TiPlaneRect.r_ytop)
499 	area.r_ytop += (abs(area.r_ytop) % growDistance);
500 
501     DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
502 
503     CIFTileOps += 1;
504     return 0;
505 }
506 
507 /*
508  * ----------------------------------------------------------------------------
509  *
510  * cifGrowEuclideanFunc --
511  *
512  * 	Called for each relevant tile during grow or shrink operations.
513  *	For growing, these are solid tiles.  For shrinking, these are
514  *	space tiles.   This routine differs from cifGrowFunc in that it
515  *	grows the minimum distance on non-Manhattan edges necessary to
516  *	create a euclidean distance to the edge of growDistance while
517  *	keeping corner points on-grid.  This requires a substantially
518  *	different algorithm from cifGrowFunc.
519  *
520  * Results:
521  *	Always returns 0 to keep the search alive.
522  *
523  * Side effects:
524  *	Scales the tile by cifScale, then expands its area by the
525  *	distance in the current CIFOp, then paints this area into
526  *	cifNewPlane using the table passed as parameter.
527  * ----------------------------------------------------------------------------
528  */
529 
530 #define GROW_NORTH 0x1
531 #define GROW_SOUTH 0x2
532 #define GROW_EAST  0x4
533 #define GROW_WEST  0x8
534 
535 #define STOP_NW 0x1	/*	   WN     EN	*/
536 #define STOP_SW 0x2	/*	NW +-------+ NE	*/
537 #define STOP_NE 0x4	/*	   |       |	*/
538 #define STOP_SE 0x8	/*	   |       |	*/
539 #define STOP_WN 0x10	/*      SW +-------+ SE	*/
540 #define STOP_WS 0x20	/*         WS     ES	*/
541 #define STOP_EN 0x40
542 #define STOP_ES 0x80
543 
544 int
cifGrowEuclideanFunc(tile,table)545 cifGrowEuclideanFunc(tile, table)
546     Tile *tile;
547     PaintResultType *table;		/* Table to be used for painting. */
548 {
549     Tile *tp;
550     Rect area, rtmp;
551     TileType oldType = TiGetTypeExact(tile);
552     unsigned char growDirs = GROW_NORTH | GROW_SOUTH | GROW_EAST | GROW_WEST;
553     unsigned char cornerDirs = 0;
554 
555     TiToRect(tile, &area);
556 
557     /* In scaling the tile, watch out for infinities!!  If something
558      * is already infinity, don't change it. */
559 
560     if (area.r_xbot > TiPlaneRect.r_xbot)
561 	area.r_xbot *= cifScale;
562     else
563 	growDirs &= ~GROW_WEST;
564     if (area.r_ybot > TiPlaneRect.r_ybot)
565 	area.r_ybot *= cifScale;
566     else
567 	growDirs &= ~GROW_SOUTH;
568     if (area.r_xtop < TiPlaneRect.r_xtop)
569 	area.r_xtop *= cifScale;
570     else
571 	growDirs &= ~GROW_EAST;
572     if (area.r_ytop < TiPlaneRect.r_ytop)
573 	area.r_ytop *= cifScale;
574     else
575 	growDirs &= ~GROW_NORTH;
576 
577     /* Grow on diagonal tiles:  grow rectangular tiles around the	*/
578     /* straight edges of the right-triangle, then copy the diagonal	*/
579     /* tile (at its original size) in the direction of the diagonal.	*/
580     /* Note:  A diagonal tile, by definition, can't have infinities.	*/
581 
582     if (oldType & TT_DIAGONAL)
583     {
584 	int growDistanceX, growDistanceY;
585 	int height, width;
586 	double hyp;
587 	int limit;
588 
589 	if (oldType & TT_SIDE)
590 	    growDirs &= ~GROW_WEST;
591 	else
592 	    growDirs &= ~GROW_EAST;
593 
594 	if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION))
595 	    growDirs &= ~GROW_SOUTH;
596 	else
597 	    growDirs &= ~GROW_NORTH;
598 
599 	/* Grow non-Manhattan edges to (the closest integer value	*/
600 	/* to) growDistance along the normal to the edge.  This		*/
601 	/* will overestimate the distance only to the minimum		*/
602 	/* amount necessary to ensure on-grid endpoints.		*/
603 
604 	width = area.r_xtop - area.r_xbot;
605 	height = area.r_ytop - area.r_ybot;
606 	hyp = sqrt((double)(width * width + height * height));
607 	growDistanceY = ceil((double)(growDistance * width) / hyp);
608 	growDistanceX = ceil((double)(growDistance * height) / hyp);
609 
610 	/* Adjust for grid limit */
611 	growDistanceX = SetValueGrid(growDistanceX);
612 	growDistanceY = SetValueGrid(growDistanceY);
613 
614 	/* Draw vertical tile to distance X */
615 
616 	rtmp = area;
617 	if (!(growDirs & GROW_EAST))  rtmp.r_xtop = rtmp.r_xbot + growDistanceX;
618 	if (!(growDirs & GROW_WEST))  rtmp.r_xbot = rtmp.r_xtop - growDistanceX;
619 	if (!(growDirs & GROW_SOUTH)) rtmp.r_ybot -= growDistance;
620 	if (!(growDirs & GROW_NORTH)) rtmp.r_ytop += growDistance;
621 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
622 
623 	/* Draw horizontal tile to distance Y */
624 
625 	rtmp = area;
626 	if (!(growDirs & GROW_EAST))  rtmp.r_xtop += growDistance;
627 	if (!(growDirs & GROW_WEST))  rtmp.r_xbot -= growDistance;
628 	if (!(growDirs & GROW_SOUTH)) rtmp.r_ybot = rtmp.r_ytop - growDistanceY;
629 	if (!(growDirs & GROW_NORTH)) rtmp.r_ytop = rtmp.r_ybot + growDistanceY;
630 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
631 
632 	/* Finally, translate, resize, and paint the diagonal tile */
633 
634 	rtmp = area;
635 
636 	if (!(growDirs & GROW_NORTH))
637 	    rtmp.r_ytop += growDistance;
638 	else
639 	    rtmp.r_ytop -= growDistanceY;
640 	if (!(growDirs & GROW_SOUTH))
641 	    rtmp.r_ybot -= growDistance;
642 	else
643 	    rtmp.r_ybot += growDistanceY;
644 	if (!(growDirs & GROW_EAST))
645 	    rtmp.r_xtop += growDistance;
646 	else
647 	    rtmp.r_xtop -= growDistanceX;
648 	if (!(growDirs & GROW_WEST))
649 	    rtmp.r_xbot -= growDistance;
650 	else
651 	    rtmp.r_xbot += growDistanceX;
652 
653 	DBNMPaintPlane(cifPlane, oldType, &rtmp, table, (PaintUndoInfo *) NULL);
654 
655 	oldType = (growDirs & GROW_EAST) ? TiGetRightType(tile) : TiGetLeftType(tile);
656     }
657     else
658 	DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
659 
660     /* Check tile corner areas for paint */
661 
662     tp = TR(tile);
663     if (TiGetLeftType(tp) == oldType) cornerDirs |= STOP_NE;
664     for (; TOP(LB(tp)) > BOTTOM(tile); tp = LB(tp));
665     if (TiGetLeftType(tp) == oldType) cornerDirs |= STOP_SE;
666 
667     tp = RT(tile);
668     if (TiGetBottomType(tp) == oldType) cornerDirs |= STOP_EN;
669     for (; RIGHT(BL(tp)) > LEFT(tile); tp = BL(tp));
670     if (TiGetBottomType(tp) == oldType) cornerDirs |= STOP_WN;
671 
672     tp = BL(tile);
673     if (TiGetRightType(tp) == oldType) cornerDirs |= STOP_SW;
674     for (; BOTTOM(RT(tp)) < TOP(tile); tp = RT(tp));
675     if (TiGetRightType(tp) == oldType) cornerDirs |= STOP_NW;
676 
677     tp = LB(tile);
678     if (TiGetTopType(tp) == oldType) cornerDirs |= STOP_WS;
679     for (; LEFT(TR(tp)) < RIGHT(tile); tp = TR(tp));
680     if (TiGetTopType(tp) == oldType) cornerDirs |= STOP_ES;
681 
682     if (growDirs & GROW_NORTH)
683     {
684 	rtmp = area;
685 	rtmp.r_ybot = area.r_ytop;
686 	rtmp.r_ytop = area.r_ytop + growDistance;
687 	if ((cornerDirs & (STOP_EN | STOP_NE)) == 0)
688 	    if (growDirs & GROW_EAST) rtmp.r_xtop += growDistance;
689 	if ((cornerDirs & (STOP_WN | STOP_NW)) == 0)
690 	    if (growDirs & GROW_WEST) rtmp.r_xbot -= growDistance;
691 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
692     }
693 
694     if (growDirs & GROW_EAST)
695     {
696 	rtmp = area;
697 	rtmp.r_xbot = area.r_xtop;
698 	rtmp.r_xtop = area.r_xtop + growDistance;
699 	if ((cornerDirs & (STOP_EN | STOP_NE)) == 0)
700 	    if (growDirs & GROW_NORTH) rtmp.r_ytop += growDistance;
701 	if ((cornerDirs & (STOP_SE | STOP_ES)) == 0)
702 	    if (growDirs & GROW_SOUTH) rtmp.r_ybot -= growDistance;
703 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
704     }
705 
706     if (growDirs & GROW_SOUTH)
707     {
708 	rtmp = area;
709 	rtmp.r_ytop = area.r_ybot;
710 	rtmp.r_ybot = area.r_ybot - growDistance;
711 	if ((cornerDirs & (STOP_SE | STOP_ES)) == 0)
712 	    if (growDirs & GROW_EAST) rtmp.r_xtop += growDistance;
713 	if ((cornerDirs & (STOP_SW | STOP_WS)) == 0)
714 	    if (growDirs & GROW_WEST) rtmp.r_xbot -= growDistance;
715 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
716     }
717 
718     if (growDirs & GROW_WEST)
719     {
720 	rtmp = area;
721 	rtmp.r_xtop = area.r_xbot;
722 	rtmp.r_xbot = area.r_xbot - growDistance;
723 	if ((cornerDirs & (STOP_NW | STOP_WN)) == 0)
724 	    if (growDirs & GROW_NORTH) rtmp.r_ytop += growDistance;
725 	if ((cornerDirs & (STOP_SW | STOP_WS)) == 0)
726 	    if (growDirs & GROW_SOUTH) rtmp.r_ybot -= growDistance;
727 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
728     }
729 
730     CIFTileOps++;
731     return 0;
732 }
733 
734 /*
735  * ----------------------------------------------------------------------------
736  *
737  * cifGrowFunc --
738  *
739  * 	Called for each relevant tile during grow or shrink operations.
740  *	For growing, these are solid tiles.  For shrinking, these are
741  *	space tiles.
742  *
743  * Results:
744  *	Always returns 0 to keep the search alive.
745  *
746  * Side effects:
747  *	Scales the tile by cifScale, then expands its area by the
748  *	distance in the current CIFOp, then paints this area into
749  *	cifNewPlane using the table passed as parameter.
750  * ----------------------------------------------------------------------------
751  */
752 
753 int
cifGrowFunc(tile,table)754 cifGrowFunc(tile, table)
755     Tile *tile;
756     PaintResultType *table;		/* Table to be used for painting. */
757 {
758     Rect area;
759     TileType oldType = TiGetTypeExact(tile);
760 
761     TiToRect(tile, &area);
762 
763     /* In scaling the tile, watch out for infinities!!  If something
764      * is already infinity, don't change it. */
765 
766     if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot *= cifScale;
767     if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot *= cifScale;
768     if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop *= cifScale;
769     if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop *= cifScale;
770 
771     /* Grow on diagonal tiles:  grow rectangular tiles around the	*/
772     /* straight edges of the right-triangle, then copy the diagonal	*/
773     /* tile (at its original size) in the direction of the diagonal.	*/
774     /* Note:  A diagonal tile, by definition, can't have infinities.	*/
775 
776     if (oldType & TT_DIAGONAL)
777     {
778 	Rect rtmp;
779 
780 	/* Grow top and bottom */
781 
782 	rtmp.r_ybot = area.r_ybot - growDistance;
783 	rtmp.r_ytop = area.r_ytop + growDistance;
784 
785 	/* Grow around left or right edge */
786 
787 	if (oldType & TT_SIDE)
788 	{
789 	    rtmp.r_xbot = area.r_xtop - growDistance;
790 	    rtmp.r_xtop = area.r_xtop + growDistance;
791 	}
792 	else
793 	{
794 	    rtmp.r_xbot = area.r_xbot - growDistance;
795 	    rtmp.r_xtop = area.r_xbot + growDistance;
796 	}
797 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
798 
799 	/* Now do the same for the other edge. */
800 
801 	rtmp.r_xbot = area.r_xbot - growDistance;
802 	rtmp.r_xtop = area.r_xtop + growDistance;
803 
804 	if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
805 	{
806 	    rtmp.r_ybot = area.r_ytop - growDistance;
807 	    rtmp.r_ytop = area.r_ytop + growDistance;
808 	}
809 	else /* bottom */
810 	{
811 	    rtmp.r_ybot = area.r_ybot - growDistance;
812 	    rtmp.r_ytop = area.r_ybot + growDistance;
813 	}
814 	DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
815 
816 	/* Finally, Move and replace the diagonal tile */
817 
818 	if (oldType & TT_SIDE)
819 	{
820 	    rtmp.r_xtop = area.r_xtop - growDistance;
821 	    rtmp.r_xbot = area.r_xbot - growDistance;
822 	}
823 	else
824 	{
825 	    rtmp.r_xtop = area.r_xtop + growDistance;
826 	    rtmp.r_xbot = area.r_xbot + growDistance;
827 	}
828 
829 	if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
830 	{
831 	    rtmp.r_ytop = area.r_ytop - growDistance;
832 	    rtmp.r_ybot = area.r_ybot - growDistance;
833 	}
834 	else	/* bottom */
835 	{
836 	    rtmp.r_ytop = area.r_ytop + growDistance;
837 	    rtmp.r_ybot = area.r_ybot + growDistance;
838 	}
839 	DBNMPaintPlane(cifPlane, oldType, &rtmp, table, (PaintUndoInfo *) NULL);
840     }
841     else
842     {
843 
844 	/* In scaling the tile, watch out for infinities!!  If something
845 	 * is already infinity, don't change it. */
846 
847 	if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot -= growDistance;
848 	if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot -= growDistance;
849 	if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop += growDistance;
850 	if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop += growDistance;
851 
852 	DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
853     }
854 
855     CIFTileOps += 1;
856     return 0;
857 }
858 
859 /*
860  * ----------------------------------------------------------------------------
861  *
862  * cifBloatFunc --
863  *
864  * 	Called once for each tile to be selectively bloated.
865  *
866  * Results:
867  *	Always returns 0 to keep the search alive.
868  *
869  * Side effects:
870  *	Uses the bloat table in the current CIFOp to expand the
871  *	tile depending on which tiles it abuts, then paints the
872  *	expanded area into the new CIF plane.  The bloat table
873  *	contains one entry for each tile type.  When that tile
874  *	type is seen next to the current tile, the area of the current
875  *	tile is bloated by the table value in that location.  The
876  *	only exception to this rule is that internal edges (between
877  *	two tiles of the same type) cause no bloating.
878  *	Note:  the original tile is scaled into CIF coordinates.
879  * ----------------------------------------------------------------------------
880  */
881 
882 int
cifBloatFunc(tile,clientData)883 cifBloatFunc(tile, clientData)
884     Tile *tile;
885     ClientData clientData;
886 {
887     Rect tileArea, cifArea, bloat;
888     TileType oldType, type, topLeftType, bottomRightType;
889     Tile *t;
890     int tilestart, tilestop, cifstart, cifstop;
891     BloatData *bloats = (BloatData *)clientData;
892     int *bloatTable = (int *)bloats->bl_distance;
893 
894     oldType = TiGetTypeExact(tile);
895     TiToRect(tile, &tileArea);
896 
897     /* Output the original area of the tile. */
898 
899     cifArea = tileArea;
900     cifArea.r_xbot *= cifScale;
901     cifArea.r_xtop *= cifScale;
902     cifArea.r_ybot *= cifScale;
903     cifArea.r_ytop *= cifScale;
904 
905     /* This is a modified version of the nonmanhattan grow function.	*/
906     /* We grow only in the direction of the diagonal.			*/
907     /* This will not work in all situations!  Corner extensions are not	*/
908     /* considered (but should be, for completeness).			*/
909 
910     if (oldType & TT_DIAGONAL)
911     {
912 	TileType otherType = (oldType & TT_SIDE) ?
913 		TiGetLeftType(tile) : TiGetRightType(tile);
914 	int dist = bloatTable[otherType];
915 
916 	/* The Euclidean grow function is identical to Euclidean bloat-or */
917 	if (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN)
918 	{
919 	    growDistance = dist;
920 	    cifGrowEuclideanFunc(tile, CIFPaintTable);
921 	}
922 	else
923 	{
924 
925 	    /* Grow top and bottom */
926 
927 	    if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
928 	    {
929 		bloat.r_ybot = cifArea.r_ytop - dist;
930 		bloat.r_ytop = cifArea.r_ytop;
931 	    }
932 	    else /* bottom */
933 	    {
934 		bloat.r_ybot = cifArea.r_ybot;
935 		bloat.r_ytop = cifArea.r_ybot + dist;
936 	    }
937 
938 	    /* Grow around left or right edge */
939 
940 	    if (oldType & TT_SIDE)
941 	    {
942 		bloat.r_xbot = cifArea.r_xbot - dist;
943 		bloat.r_xtop = cifArea.r_xtop;
944 	    }
945 	    else
946 	    {
947 		bloat.r_xbot = cifArea.r_xbot;
948 		bloat.r_xtop = cifArea.r_xtop + dist;
949 	    }
950 	    DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL);
951 
952 	    /* Now do the same for the left or right edge. */
953 
954 	    if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
955 	    {
956 		bloat.r_ybot = cifArea.r_ybot - dist;
957 		bloat.r_ytop = cifArea.r_ytop;
958 	    }
959 	    else /* bottom */
960 	    {
961 		bloat.r_ybot = cifArea.r_ybot;
962 		bloat.r_ytop = cifArea.r_ytop + dist;
963 	    }
964 
965 	    if (oldType & TT_SIDE)
966 	    {
967 		bloat.r_xbot = cifArea.r_xtop - dist;
968 		bloat.r_xtop = cifArea.r_xtop;
969 	    }
970 	    else
971 	    {
972 		bloat.r_xbot = cifArea.r_xbot;
973 		bloat.r_xtop = cifArea.r_xbot + dist;
974 	    }
975 	    DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL);
976 
977 	    /* Finally, Move and replace the diagonal tile */
978 
979 	    if (oldType & TT_SIDE)
980 	    {
981 		bloat.r_xtop = cifArea.r_xtop - dist;
982 		bloat.r_xbot = cifArea.r_xbot - dist;
983 	    }
984 	    else
985 	    {
986 		bloat.r_xtop = cifArea.r_xtop + dist;
987 		bloat.r_xbot = cifArea.r_xbot + dist;
988 	    }
989 
990 	    if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
991 	    {
992 		bloat.r_ytop = cifArea.r_ytop - dist;
993 		bloat.r_ybot = cifArea.r_ybot - dist;
994 	    }
995 	    else	/* bottom */
996 	    {
997 		bloat.r_ytop = cifArea.r_ytop + dist;
998 		bloat.r_ybot = cifArea.r_ybot + dist;
999 	    }
1000 	    DBNMPaintPlane(cifPlane, oldType, &bloat, CIFPaintTable,
1001 			(PaintUndoInfo *) NULL);
1002 	}
1003     }
1004     else
1005 	DBNMPaintPlane(cifPlane, oldType, &cifArea, CIFPaintTable,
1006 			(PaintUndoInfo *) NULL);
1007 
1008     /* Go around the tile, scanning the neighbors along each side.
1009      * Start with the left side, and output the bloats along that
1010      * side, if any.
1011      */
1012 
1013     tilestop = tileArea.r_ytop;
1014     cifstop = cifArea.r_ytop;
1015     type = oldType;
1016 
1017     /* If the tile type doesn't exist on the left side, skip */
1018     if (oldType & TT_DIAGONAL)
1019     {
1020 	type = TiGetLeftType(tile);
1021 	if (oldType & TT_SIDE)
1022 	{
1023 	    if (oldType & TT_DIRECTION)
1024 	    {
1025 		topLeftType = type;
1026 		goto dotop;
1027 	    }
1028 	    else
1029 	    {
1030 		tilestop = tileArea.r_ybot;
1031 		cifstop = cifArea.r_ybot;
1032 		type = TiGetBottomType(tile);
1033 	    }
1034 	}
1035     }
1036 
1037     bloat.r_ybot = cifArea.r_ybot - bloatTable[TiGetRightType(LB(tile))];
1038     bloat.r_xtop = cifArea.r_xbot;
1039     for (t = BL(tile); BOTTOM(t) < TOP(tile); t = RT(t))
1040     {
1041 	if (BOTTOM(t) >= tilestop) continue;
1042 	topLeftType = TiGetRightType(t);
1043 	bloat.r_xbot = bloat.r_xtop - bloatTable[topLeftType];
1044 	if (TOP(t) > tilestop)
1045 	    bloat.r_ytop = cifstop;
1046 	else bloat.r_ytop = cifScale * TOP(t);
1047 	if ((bloatTable[topLeftType] != 0) && (topLeftType != type))
1048 	    DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1049 		(PaintUndoInfo *) NULL);
1050 	bloat.r_ybot = bloat.r_ytop;
1051     }
1052 
1053     /* Now do the top side.  Use the type of the top-left tile to
1054      * side-extend the left end of the top bloat in order to match
1055      * things up at the corner.
1056      */
1057 
1058 dotop:
1059     cifstart = cifArea.r_xtop;
1060     tilestart = tileArea.r_xtop;
1061 
1062     /* If the tile type doesn't exist on the top side, skip */
1063     if (oldType & TT_DIAGONAL)
1064     {
1065 	type = TiGetTopType(tile);
1066 	if (((oldType & TT_SIDE) >> 1) != (oldType & TT_DIRECTION))
1067 	{
1068 	    if (oldType & TT_SIDE)
1069 		goto doright;
1070 	    else
1071 	    {
1072 		cifstart = cifArea.r_xbot;
1073 		tilestart = tileArea.r_xbot;
1074 		type = TiGetLeftType(tile);
1075 	    }
1076 	}
1077     }
1078 
1079     bloat.r_ybot = cifArea.r_ytop;
1080     bloat.r_xtop = cifstart;
1081     for (t = RT(tile); RIGHT(t) > LEFT(tile); t = BL(t))
1082     {
1083 	TileType otherType;
1084 	if (LEFT(t) >= tilestart) continue;
1085 	otherType = TiGetBottomType(t);
1086 	bloat.r_ytop = bloat.r_ybot + bloatTable[otherType];
1087 	if (LEFT(t) <= tileArea.r_xbot)
1088 	    bloat.r_xbot = cifArea.r_xbot - bloatTable[topLeftType];
1089 	else bloat.r_xbot = cifScale * LEFT(t);
1090 	if ((bloatTable[otherType] != 0) && (otherType != type))
1091 	    DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1092 		(PaintUndoInfo *) NULL);
1093 	bloat.r_xtop = bloat.r_xbot;
1094     }
1095 
1096     /* Now do the right side. */
1097 
1098 doright:
1099     tilestop = tileArea.r_ybot;
1100     cifstop = cifArea.r_ybot;
1101 
1102     /* If the tile type doesn't exist on the right side, skip */
1103     if (oldType & TT_DIAGONAL)
1104     {
1105 	type = TiGetRightType(tile);
1106 	if (!(oldType & TT_SIDE))
1107 	{
1108 	    if (oldType & TT_DIRECTION)
1109 	    {
1110 		bottomRightType = type;
1111 		goto dobottom;
1112 	    }
1113 	    else
1114 	    {
1115 		tilestop = tileArea.r_ytop;
1116 		cifstop = cifArea.r_ytop;
1117 		type = TiGetTopType(tile);
1118 	    }
1119 	}
1120     }
1121 
1122     bloat.r_ytop = cifArea.r_ytop + bloatTable[TiGetLeftType(RT(tile))];
1123     bloat.r_xbot = cifArea.r_xtop;
1124     for (t = TR(tile); TOP(t) > BOTTOM(tile); t = LB(t))
1125     {
1126 	if (TOP(t) <= tilestop) continue;
1127 	bottomRightType = TiGetLeftType(t);
1128 	bloat.r_xtop = bloat.r_xbot + bloatTable[bottomRightType];
1129 	if (BOTTOM(t) < tilestop)
1130 	    bloat.r_ybot = cifstop;
1131 	else bloat.r_ybot = cifScale * BOTTOM(t);
1132 	if ((bloatTable[bottomRightType] != 0) && (bottomRightType != type))
1133 	    DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1134 		(PaintUndoInfo *) NULL);
1135 	bloat.r_ytop = bloat.r_ybot;
1136     }
1137 
1138     /* Now do the bottom side.  Use the type of the bottom-right tile
1139      * to side-extend the right end of the bottom bloat in order to match
1140      * things up at the corner.
1141      */
1142 
1143 dobottom:
1144     cifstart = cifArea.r_xbot;
1145     tilestart = tileArea.r_xbot;
1146 
1147     /* If the tile type doesn't exist on the bottom side, skip */
1148     if (oldType & TT_DIAGONAL)
1149     {
1150 	type = TiGetBottomType(tile);
1151 	if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION))
1152 	{
1153 	    if (!(oldType & TT_DIRECTION))
1154 		goto endbloat;
1155 	    else
1156 	    {
1157 		cifstart = cifArea.r_xtop;
1158 		tilestart = tileArea.r_xtop;
1159 		type = TiGetRightType(tile);
1160 	    }
1161 	}
1162     }
1163 
1164     bloat.r_ytop = cifArea.r_ybot;
1165     bloat.r_xbot = cifstart;
1166     for (t = LB(tile); LEFT(t) < RIGHT(tile); t = TR(t))
1167     {
1168 	TileType otherType;
1169 	if (RIGHT(t) <= tilestart) continue;
1170 	otherType = TiGetTopType(t);
1171 	bloat.r_ybot = bloat.r_ytop - bloatTable[otherType];
1172 	if (RIGHT(t) >= tileArea.r_xtop)
1173 	    bloat.r_xtop = cifArea.r_xtop + bloatTable[bottomRightType];
1174 	else bloat.r_xtop = cifScale * RIGHT(t);
1175 	if ((bloatTable[otherType] != 0) && (otherType != type))
1176 	    DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1177 		(PaintUndoInfo *) NULL);
1178 	bloat.r_xbot = bloat.r_xtop;
1179     }
1180 
1181 endbloat:
1182     CIFTileOps += 1;
1183     return 0;
1184 }
1185 
1186 #define CIF_PENDING     0
1187 #define CIF_UNPROCESSED CLIENTDEFAULT
1188 #define CIF_PROCESSED   1
1189 #define CIF_IGNORE   	2
1190 
1191 #define PUSHTILE(tp, stack) \
1192     if ((tp)->ti_client == (ClientData) CIF_UNPROCESSED) { \
1193 	(tp)->ti_client = (ClientData) CIF_PENDING; \
1194 	STACKPUSH((ClientData) (tp), stack); \
1195     }
1196 
1197 /*
1198  *-------------------------------------------------------
1199  *
1200  * cifProcessResetFunc --
1201  *
1202  *	Unmark tiles
1203  *
1204  * Results:	Return 0 to keep the search going.
1205  *
1206  *-------------------------------------------------------
1207  */
1208 
1209 int
cifProcessResetFunc(tile,clientData)1210 cifProcessResetFunc(tile, clientData)
1211     Tile *tile;
1212     ClientData clientData;	/* unused */
1213 {
1214     tile->ti_client = (ClientData) CIF_UNPROCESSED;
1215     return 0;
1216 }
1217 
1218 /*
1219  *-------------------------------------------------------
1220  *
1221  * cifFoundFunc --
1222  *
1223  *	Find the first tile in the given area.
1224  *
1225  * Results:
1226  *	Return 1 to stop the search and process.
1227  *	Set clientData to the tile found.
1228  *
1229  *-------------------------------------------------------
1230  */
1231 
1232 int
cifFoundFunc(tile,BloatStackPtr)1233 cifFoundFunc(tile, BloatStackPtr)
1234     Tile *tile;
1235     Stack **BloatStackPtr;
1236 {
1237     PUSHTILE(tile, *BloatStackPtr);
1238     return 0;
1239 }
1240 
1241 /* Data structure for bloat-all function */
1242 typedef struct _bloatStruct {
1243     CIFOp	*op;
1244     CellDef	*def;
1245     TileTypeBitMask connect;
1246     Plane       **temps;
1247 } BloatStruct;
1248 
1249 /*
1250  * ----------------------------------------------------------------------------
1251  *
1252  * cifBloatAllFunc --
1253  *
1254  * 	Called once for each tile to be selectively bloated
1255  *	using the CIFOP_BLOATALL operation.
1256  *
1257  * Results:
1258  *	Always returns 0 to keep the search alive.
1259  *
1260  * Side effects:
1261  *	Uses the bloat table in the current CIFOp to expand the tile,
1262  *	depending on which tiles it abuts.  All bordering material that
1263  *	has bl_distance = 1 is painted into the result plane.
1264  *
1265  * ----------------------------------------------------------------------------
1266  */
1267 
1268 int
cifBloatAllFunc(tile,bls)1269 cifBloatAllFunc(tile, bls)
1270     Tile *tile;			/* The tile to be processed. */
1271     BloatStruct *bls;
1272 {
1273     Rect area;
1274     TileTypeBitMask *connect;
1275     Tile *t, *tp;
1276     TileType type, ttype;
1277     BloatData *bloats;
1278     int i, locScale;
1279     PlaneMask pmask;
1280     CIFOp *op;
1281     CellDef *def;
1282     Plane **temps;
1283     static Stack *BloatStack = (Stack *)NULL;
1284 
1285     op = bls->op;
1286     def = bls->def;
1287     temps = bls->temps;
1288     connect = &bls->connect;
1289     bloats = (BloatData *)op->co_client;
1290 
1291     /* This search function is based on drcCheckArea */
1292 
1293     if (BloatStack == (Stack *)NULL)
1294 	BloatStack = StackNew(64);
1295 
1296     /* If the type of the tile to be processed is not in the same plane	*/
1297     /* as the bloat type(s), then find any tile under the tile to be	*/
1298     /* processed that belongs to the connect mask, and use that as the	*/
1299     /* starting tile.							*/
1300 
1301     t = tile;
1302     type = TiGetType(tile);
1303     if (type == CIF_SOLIDTYPE)
1304     {
1305 	pmask = 0;
1306 	if (bloats->bl_plane < 0)   /* Bloat types are CIF types */
1307 	    locScale = 1;
1308 	else
1309 	    locScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
1310 
1311 	/* Get the tile into magic database coordinates if it's in CIF coords */
1312 	TiToRect(tile, &area);
1313 	area.r_xbot /= locScale;
1314 	area.r_xtop /= locScale;
1315 	area.r_ybot /= locScale;
1316 	area.r_ytop /= locScale;
1317     }
1318     else
1319     {
1320 	int pNum = DBPlane(type);
1321 	pmask = (bloats->bl_plane < 0) ? 0 :
1322 		CoincidentPlanes(connect, PlaneNumToMaskBit(pNum));
1323 	if (pmask == 0) TiToRect(tile, &area);
1324 	if (bloats->bl_plane < 0)
1325 	{
1326 	    /* Get the tile into CIF database coordinates if it's in magic coords */
1327 	    area.r_xbot *= cifScale;
1328 	    area.r_xtop *= cifScale;
1329 	    area.r_ybot *= cifScale;
1330 	    area.r_ytop *= cifScale;
1331 	    locScale = 1;
1332 	}
1333 	else
1334 	{
1335 	    locScale = cifScale;
1336 	}
1337     }
1338     if (pmask == 0)
1339     {
1340 	if (bloats->bl_plane < 0)   /* Bloat types are CIF types */
1341 	{
1342 	    /* This expands the area to the OR of all temp layers specified */
1343 	    /* which may or may not be useful;  normally one would expand   */
1344 	    /* into a single layer if a temp layer is specified.	    */
1345 
1346 	    for (ttype = 0; ttype < TT_MAXTYPES; ttype++, temps++)
1347 		if (bloats->bl_distance[ttype] > 0)
1348 		    (void) DBSrPaintArea((Tile *)NULL, *temps, &area,
1349 				&CIFSolidBits, cifFoundFunc, (ClientData)(&BloatStack));
1350 	}
1351 	else
1352 	    DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &area,
1353 		    connect, cifFoundFunc, (ClientData)(&BloatStack));
1354     }
1355     else
1356 	PUSHTILE(t, BloatStack);
1357 
1358     while (!StackEmpty(BloatStack))
1359     {
1360 	t = (Tile *) STACKPOP(BloatStack);
1361 	if (t->ti_client != (ClientData)CIF_PENDING) continue;
1362         t->ti_client = (ClientData)CIF_PROCESSED;
1363 
1364 	/* Get the tile into CIF coordinates. */
1365 
1366 	TiToRect(t, &area);
1367 	area.r_xbot *= locScale;
1368 	area.r_ybot *= locScale;
1369 	area.r_xtop *= locScale;
1370 	area.r_ytop *= locScale;
1371 
1372 	DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
1373 		CIFPaintTable, (PaintUndoInfo *) NULL);
1374 
1375 	/* Top */
1376 	for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
1377 	    if (TTMaskHasType(connect, TiGetBottomType(tp)))
1378 		PUSHTILE(tp, BloatStack);
1379 
1380 	/* Left */
1381 	for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
1382 	    if (TTMaskHasType(connect, TiGetRightType(tp)))
1383 		PUSHTILE(tp, BloatStack);
1384 
1385 	/* Bottom */
1386 	for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
1387 	    if (TTMaskHasType(connect, TiGetTopType(tp)))
1388 		PUSHTILE(tp, BloatStack);
1389 
1390 	/* Right */
1391 	for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
1392 	    if (TTMaskHasType(connect, TiGetLeftType(tp)))
1393 		PUSHTILE(tp, BloatStack);
1394     }
1395 
1396     /* Clear the tiles that were processed */
1397 
1398     tile->ti_client = (ClientData)CIF_UNPROCESSED;
1399     STACKPUSH(tile, BloatStack);
1400     while (!StackEmpty(BloatStack))
1401     {
1402 	t = (Tile *) STACKPOP(BloatStack);
1403 
1404 	/* Top */
1405 	for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
1406 	    if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1407 	    {
1408 		tp->ti_client = (ClientData)CIF_UNPROCESSED;
1409 		STACKPUSH(tp, BloatStack);
1410 	    }
1411 
1412 	/* Left */
1413 	for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
1414 	    if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1415 	    {
1416 		tp->ti_client = (ClientData)CIF_UNPROCESSED;
1417 		STACKPUSH(tp, BloatStack);
1418 	    }
1419 
1420 	/* Bottom */
1421 	for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
1422 	    if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1423 	    {
1424 		tp->ti_client = (ClientData)CIF_UNPROCESSED;
1425 		STACKPUSH(tp, BloatStack);
1426 	    }
1427 
1428 	/* Right */
1429 	for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
1430 	    if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1431 	    {
1432 		tp->ti_client = (ClientData)CIF_UNPROCESSED;
1433 		STACKPUSH(tp, BloatStack);
1434 	    }
1435     }
1436 
1437     return 0;	/* Keep the search alive. . . */
1438 }
1439 
1440 /* Data structure to pass plane and minimum width to the callback function */
1441 typedef struct _bridgeStruct {
1442     Plane       *plane;
1443     BridgeData	*bridge;
1444 } BridgeStruct;
1445 
1446 /* Bridge Check data structure */
1447 typedef struct _bridgeCheckStruct {
1448    Tile *tile;		/* Tile that triggered search (ignore this tile) */
1449    Rect *area;		/* Area of search */
1450    int	direction;	/* What outside corner to look for */
1451    Tile *violator;	/* Return the violator tile in this space */
1452    TileType checktype;	/* Type to check for, either TT_SPACE or CIF_SOLIDTYPE */
1453 } BridgeCheckStruct;
1454 
1455 /* Direction flags */
1456 #define BRIDGE_NW	1
1457 #define BRIDGE_SW	2
1458 
1459 /*
1460  * ----------------------------------------------------------------------------
1461  *
1462  * Function that returns the Euclidean distance corresponding to a manhattan
1463  * distance of the given width, at 45 degrees.
1464  *
1465  * This is used by the bridging method to keep the amount of extra material
1466  * added to a minimum.
1467  *
1468  * ----------------------------------------------------------------------------
1469  */
1470 
1471 int
GetEuclideanWidthGrid(width)1472 GetEuclideanWidthGrid(width)
1473     int width;
1474 {
1475     int weuclid;
1476     int delta;
1477     int limit;
1478 
1479     limit = CIFCurStyle->cs_gridLimit;
1480 
1481     weuclid = (int)(ceil((double)width * 0.70711));
1482     if (CIFCurStyle && (limit > 1))
1483     {
1484 	delta = weuclid % limit;
1485 	if (delta > 0)
1486 	{
1487 	    weuclid -= delta;
1488 	    weuclid += limit;
1489 	}
1490     }
1491     return weuclid;
1492 }
1493 
1494 /*
1495  * ----------------------------------------------------------------------------
1496  *
1497  * GetExpandedAreaGrid --
1498  *
1499  *	Given a pointer "area" to a Rect and a minimum layer width "width",
1500  *	find the minimum size rectangle that expands "area" in all directions
1501  *	equally to ensure that the length of the diagonal of the expanded
1502  *	area is greater than or equal to "width".  This is used by the
1503  *	"bridge" operator to ensure that the bridging rectangle meets the
1504  *	minimum layer width requirement.
1505  *
1506  * Results:
1507  *	None.
1508  *
1509  * Side effects:
1510  *	The Rect structure pointed to by "area" may be altered.
1511  *
1512  * Notes:
1513  *	The calculation needed depends on the geometry.  If there is a
1514  *	horizontal gap between the tiles, then the bridging shape must
1515  *	be as tall as the minimum width rule;  this is the vertical
1516  *	case (horiz = FALSE).  If there is a vertical gap between the
1517  *	tiles, then the bridging shape must be as wide as the minimum
1518  *	width rule;  this is the horizontal case (horiz = TRUE).  Then
1519  *	calculate the length of the bridging shape in the other direction
1520  *	needed to ensure that the join of the bridging shape and the
1521  *	preexisting shapes is always wide enough to satisfy the width
1522  *	rule.  Which calculation is needed depends on whether the shapes
1523  *	are catecorner (overlap = FALSE) or overlapping in one direction
1524  *	(overlap = TRUE).
1525  *
1526  * ----------------------------------------------------------------------------
1527  */
1528 
1529 void
GetExpandedAreaGrid(wrule,space,area)1530 GetExpandedAreaGrid(wrule, space, area)
1531     int wrule;
1532     bool space;
1533     Rect *area;
1534 {
1535     bool horiz;
1536     bool overlap;
1537     Rect r;
1538 
1539     int width, height, dx, dy, a, b, delta, dx2, dy2, limit;
1540 
1541     overlap = FALSE;
1542     if (area->r_xbot > area->r_xtop)
1543     {
1544 	overlap = TRUE;
1545 	horiz = (space) ? FALSE : TRUE;
1546     }
1547     if (area->r_ybot > area->r_ytop)
1548     {
1549 	overlap = TRUE;
1550 	horiz = (space) ? TRUE : FALSE;
1551     }
1552 
1553     GeoCanonicalRect(area, &r);
1554     width = r.r_xtop - r.r_xbot;
1555     height = r.r_ytop - r.r_ybot;
1556 
1557     if (overlap == FALSE)
1558 	horiz = (width > height);
1559 
1560     if (horiz)
1561     {
1562 	a = wrule - width;
1563 	dx = (int)ceilf((float)a / 2.0);
1564 	if (overlap || space)
1565 	    b = wrule * wrule - (width + dx) * (width + dx);
1566 	else
1567 	    b = wrule * wrule - dx * dx;
1568 	if (space && !overlap)
1569 	    dy = (int)ceilf(sqrtf((float)b) - height);
1570 	else
1571 	    dy = (int)ceilf(sqrtf((float)b));
1572 
1573 	b = wrule * wrule - width * width;
1574 	dy2 = (int)ceilf((sqrtf((float)b) - height) / 2.0);
1575 	if (dy2 > dy) dy = dy2;
1576     }
1577     else
1578     {
1579 	a = wrule - height;
1580 	dy = (int)ceilf((float)a / 2.0);
1581 	if (overlap || space)
1582 	    b = wrule * wrule - (height + dy) * (height + dy);
1583 	else
1584 	    b = wrule * wrule - dy * dy;
1585 	if (space && !overlap)
1586 	    dx = (int)ceilf(sqrtf((float)b) - width);
1587 	else
1588 	    dx = (int)ceilf(sqrtf((float)b));
1589 
1590 	b = wrule * wrule - height * height;
1591 	dx2 = (int)ceilf((sqrtf((float)b) - width) / 2.0);
1592 	if (dx2 > dx) dx = dx2;
1593     }
1594 
1595     r.r_xbot -= dx;
1596     r.r_xtop += dx;
1597     r.r_ybot -= dy;
1598     r.r_ytop += dy;
1599 
1600     limit = CIFCurStyle->cs_gridLimit;
1601 
1602     if (CIFCurStyle && (limit > 1))
1603     {
1604 	delta = r.r_xbot % limit;
1605 	if (delta > 0)
1606 	    r.r_xbot -= delta;
1607 	else if (delta < 0)
1608 	    r.r_xbot -= limit + delta;
1609 
1610 	delta = r.r_xtop % limit;
1611 	if (delta > 0)
1612 	    r.r_xtop += limit - delta;
1613 	else if (delta < 0)
1614 	    r.r_xtop -= delta;
1615 
1616 	delta = r.r_ybot % limit;
1617 	if (delta > 0)
1618 	    r.r_ybot -= delta;
1619 	else if (delta < 0)
1620 	    r.r_ybot -= limit + delta;
1621 
1622 	delta = r.r_ytop % limit;
1623 	if (delta > 0)
1624 	    r.r_ytop += limit - delta;
1625 	else if (delta < 0)
1626 	    r.r_ytop -= delta;
1627     }
1628 
1629     *area = r;
1630 }
1631 
1632 /*
1633  * ----------------------------------------------------------------------------
1634  *
1635  * cifBridgeFunc1 --
1636  *
1637  * 	Called for each relevant tile during bridge operations.  The
1638  *	bridge operation is responsible for preventing a grow-shrink
1639  *	pair of operations from leaving width or spacing DRC errors,
1640  *	which happens when tiles are in a catecorner position from
1641  *	each other.  The bridge operation adds a bridge of material
1642  *	between the two tiles that solves spacing requirements between
1643  *      the two tiles while satisfying the minimum width requirements,
1644  *	adding a minimum amount of material to do so.
1645  *
1646  *	The current version of this routine adds material on a stair-step
1647  *	pattern;  preferably this should be extended to create material
1648  *	at allowed angles, where the allowed angles (90, 45, or any) are
1649  *	specified as an option to the bridge statement in the tech file.
1650  *
1651  *	GrowDistance is equal to the spacing rule distance needing to be
1652  *	satisfied.
1653  *
1654  * Results:
1655  *	Always returns 0 to keep the search alive.
1656  *
1657  * Side effects:
1658  *	Paints into cifNewPlane.  Tiles in old plane are tagged with
1659  *	a static value in ClientData, which does not need to be reset
1660  *	since the old plane will be free'd.
1661  * ----------------------------------------------------------------------------
1662  */
1663 
1664 int
cifBridgeFunc1(tile,brs)1665 cifBridgeFunc1(tile, brs)
1666     Tile *tile;
1667     BridgeStruct *brs;
1668 {
1669     Plane *plane = brs->plane;
1670     Rect area;
1671     Tile *tp1, *tp2, *tpx;
1672     int width = brs->bridge->br_width;
1673     int spacing = growDistance;
1674     BridgeCheckStruct brcs;
1675     int cifBridgeCheckFunc();	/* Forward reference */
1676 
1677     /* If tile is marked, then it has been handled, so ignore it */
1678     if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
1679 
1680     /* Find each tile outside corner (only two cases need to be checked) */
1681 
1682     /* Check for NE outside corner */
1683     tp1 = TR(tile);  /* Tile on right side at the top of this tile */
1684     tp2 = RT(tile);  /* Tile on top side at the right of this tile */
1685     if ((TiGetLeftType(tp1) == TT_SPACE) &&
1686 	    (TiGetBottomType(tp2) == TT_SPACE))
1687     {
1688 	/* Set search box */
1689 	area.r_xbot = RIGHT(tile) - width;
1690 	area.r_xtop = RIGHT(tile) + spacing;
1691 	area.r_ybot = TOP(tile) - width;
1692 	area.r_ytop = TOP(tile) + spacing;
1693 
1694 	/* Find violator tiles */
1695 	brcs.tile = tile;
1696 	brcs.area = &area;
1697 	brcs.direction = BRIDGE_SW;
1698 	brcs.checktype = TT_SPACE;
1699 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
1700 		    &CIFSolidBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1701 	{
1702 	    tpx = brcs.violator;
1703 
1704 	    area.r_xbot = RIGHT(tile);
1705 	    area.r_ybot = TOP(tile);
1706 	    area.r_xtop = LEFT(tpx);
1707 	    area.r_ytop = BOTTOM(tpx);
1708 
1709  	    GetExpandedAreaGrid(width, FALSE, &area);
1710 
1711 	    /* Trivial implementation: fill box */
1712 	    /* (to do: use stairstep to avoid filling unnecessary areas) */
1713 	    DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1714 	}
1715     }
1716 
1717     /* Check for SE outside corner */
1718     for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
1719     for (tp2 = LB(tile); RIGHT(tp1) < RIGHT(tile); tp2 = TR(tp2));
1720     if ((TiGetLeftType(tp1) == TT_SPACE) &&
1721 	    (TiGetTopType(tp2) == TT_SPACE))
1722     {
1723 	/* Set search box */
1724 	area.r_xbot = RIGHT(tile) - width;
1725 	area.r_xtop = RIGHT(tile) + spacing;
1726 	area.r_ybot = BOTTOM(tile) - spacing;
1727 	area.r_ytop = BOTTOM(tile) + width;
1728 
1729 	/* Find violator tiles */
1730 	brcs.tile = tile;
1731 	brcs.area = &area;
1732 	brcs.direction = BRIDGE_NW;
1733 	brcs.checktype = TT_SPACE;
1734 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
1735 		    &CIFSolidBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1736 	{
1737 	    tpx = brcs.violator;
1738 
1739 	    area.r_xbot = RIGHT(tile);
1740 	    area.r_ybot = TOP(tpx);
1741 	    area.r_xtop = LEFT(tpx);
1742 	    area.r_ytop = BOTTOM(tile);
1743 
1744  	    GetExpandedAreaGrid(width, FALSE, &area);
1745 
1746 	    /* Trivial implementation: fill box */
1747 	    /* (to do: use stairstep to avoid filling unnecessary areas) */
1748 	    DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1749 	}
1750     }
1751     return 0;
1752 }
1753 
1754 /*
1755  * ----------------------------------------------------------------------------
1756  *
1757  * cifBridgeFunc2 --
1758  *
1759  * 	Called for each relevant tile during bridge operations.  The
1760  *	bridge operation is responsible for preventing a grow-shrink
1761  *	pair of operations from leaving width or spacing DRC errors,
1762  *	which happens when tiles are overlapping at a corner with the
1763  *	overlap failing to meet the minimum width requirement.  The
1764  *	bridge operation adds a bridge of material over the pinch
1765  *	point that solves the minimum width requirement, adding a
1766  *	minimum amount of material to do so.
1767  *
1768  *	The current version of this routine adds material on a stair-step
1769  *	pattern;  preferably this should be extended to create material
1770  *	at allowed angles, where the allowed angles (90, 45, or any) are
1771  *	specified as an option to the bridge statement in the tech file.
1772  *
1773  *	growDistance is equal to the spacing rule distance needing to be
1774  *	satisfied.
1775  *
1776  * Results:
1777  *	Always returns 0 to keep the search alive.
1778  *
1779  * Side effects:
1780  *	Paints into cifNewPlane.  Tiles in old plane are tagged with
1781  *	a static value in ClientData, which does not need to be reset
1782  *	since the old plane will be free'd.
1783  * ----------------------------------------------------------------------------
1784  */
1785 
1786 int
cifBridgeFunc2(tile,brs)1787 cifBridgeFunc2(tile, brs)
1788     Tile *tile;
1789     BridgeStruct *brs;
1790 {
1791     Plane *plane = brs->plane;
1792     Rect area;
1793     Tile *tp1, *tp2, *tpx;
1794     int width = brs->bridge->br_width;
1795     int wtest;
1796     int spacing = growDistance;
1797     BridgeCheckStruct brcs;
1798     int cifBridgeCheckFunc();	/* Forward reference */
1799 
1800     /* If tile is marked, then it has been handled, so ignore it */
1801     if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
1802 
1803     /* Find each tile outside corner (only two cases need to be checked) */
1804 
1805     /* Check for NE outside corner */
1806     tp1 = TR(tile);  /* Tile on right side at the top of this tile */
1807     tp2 = RT(tile);  /* Tile on top side at the right of this tile */
1808     if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
1809 	    (TiGetBottomType(tp2) == CIF_SOLIDTYPE))
1810     {
1811 	/* Set search box */
1812 	area.r_xbot = RIGHT(tile) - spacing;
1813 	area.r_xtop = RIGHT(tile) + width;
1814 	area.r_ybot = TOP(tile) - spacing;
1815 	area.r_ytop = TOP(tile) + width;
1816 
1817 	/* Find violator tiles */
1818 	brcs.tile = tile;
1819 	brcs.area = &area;
1820 	brcs.direction = BRIDGE_SW;
1821 	brcs.checktype = CIF_SOLIDTYPE;
1822 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
1823 		    &DBSpaceBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1824 	{
1825 	    tpx = brcs.violator;
1826 
1827 	    area.r_xbot = RIGHT(tile);
1828 	    area.r_ybot = TOP(tile);
1829 	    area.r_xtop = LEFT(tpx);
1830 	    area.r_ytop = BOTTOM(tpx);
1831 
1832 	    GetExpandedAreaGrid(width, TRUE, &area);
1833 
1834 	    /* Trivial implementation: fill box */
1835 	    /* (to do: use stairstep to avoid filling unnecessary areas) */
1836 	    DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1837 	}
1838     }
1839 
1840     /* Check for SE outside corner */
1841     for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
1842     for (tp2 = LB(tile); RIGHT(tp2) < RIGHT(tile); tp2 = TR(tp2));
1843     if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
1844 	    (TiGetTopType(tp2) == CIF_SOLIDTYPE))
1845     {
1846 	/* Set search box */
1847 	area.r_xbot = RIGHT(tile) - spacing;
1848 	area.r_xtop = RIGHT(tile) + width;
1849 	area.r_ybot = BOTTOM(tile) - width;
1850 	area.r_ytop = BOTTOM(tile) + spacing;
1851 
1852 	/* Find violator tiles */
1853 	brcs.tile = tile;
1854 	brcs.area = &area;
1855 	brcs.direction = BRIDGE_NW;
1856 	brcs.checktype = CIF_SOLIDTYPE;
1857 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
1858 		    &DBSpaceBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1859 	{
1860 	    tpx = brcs.violator;
1861 
1862 	    area.r_xbot = RIGHT(tile);
1863 	    area.r_ybot = TOP(tpx);
1864 	    area.r_xtop = LEFT(tpx);
1865 	    area.r_ytop = BOTTOM(tile);
1866 
1867 	    GetExpandedAreaGrid(width, TRUE, &area);
1868 
1869 	    /* Trivial implementation: fill box */
1870 	    /* (to do: use stairstep to avoid filling unnecessary areas) */
1871 	    DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1872 	}
1873     }
1874     return 0;
1875 }
1876 
1877 /*
1878  *-----------------------------------------------------------------------
1879  * Callback function for cifBridgeFunc1 and cifBridgeFunc2 to find if
1880  * there are violator cells in the search area.	 If a violator cell is
1881  * found, then put the tile pointer in the BridgeCheckStruct and return
1882  * value 1 to stop the search.	Otherwise return 0 to keep going.
1883  *-----------------------------------------------------------------------
1884  */
1885 
1886 int
cifBridgeCheckFunc(tile,brcs)1887 cifBridgeCheckFunc(tile, brcs)
1888     Tile *tile;
1889     BridgeCheckStruct *brcs;
1890 {
1891     int dir = brcs->direction;
1892     Tile *self = brcs->tile;
1893     Tile *tp1, *tp2;
1894     TileType checktype = brcs->checktype;
1895 
1896     if (self == tile) return 0;	    /* Ignore the triggering tile */
1897 
1898     switch (dir) {
1899 	case BRIDGE_NW:
1900 	    /* Ignore tile if NW corner is not in the search area */
1901 	    for (tp1 = RT(tile); LEFT(tp1) > LEFT(tile); tp1 = BL(tp1));
1902 	    if (LEFT(tile) <= brcs->area->r_xbot || TOP(tile) >= brcs->area->r_ytop)
1903 		break;
1904 	    /* Check that this is not a false corner */
1905 	    else if (TiGetBottomType(tp1) == TiGetTopType(tile))
1906 		break;
1907 	    /* Ignore tile if split, and SE corner is clipped */
1908 	    if (TiGetRightType(tile) == checktype || TiGetBottomType(tile) == checktype)
1909 		break;
1910 	    for (tp2 = BL(tile); TOP(tp2) < TOP(tile); tp2 = RT(tp2));
1911 	    if ((TiGetBottomType(tp1) == checktype) &&
1912 		    (TiGetRightType(tp2) == checktype))
1913 	    {
1914 		brcs->violator = tile;
1915 		return 1;	/* Violator found */
1916 	    }
1917 	    break;
1918 	case BRIDGE_SW:
1919 	    /* Ignore tile if SW corner is not in the search area */
1920 	    tp1 = LB(tile);
1921 	    if (LEFT(tile) <= brcs->area->r_xbot || BOTTOM(tile) <= brcs->area->r_ybot)
1922 		break;
1923 	    /* Check that this is not a false corner */
1924 	    else if (TiGetTopType(tp1) == TiGetBottomType(tile))
1925 		break;
1926 	    /* Ignore tile if split, and NE corner is clipped */
1927 	    if (TiGetRightType(tile) == checktype || TiGetTopType(tile) == checktype)
1928 		break;
1929 	    tp2 = BL(tile);
1930 	    if ((TiGetTopType(tp1) == checktype) ||
1931 		    (TiGetRightType(tp2) == checktype))
1932 	    {
1933 		brcs->violator = tile;
1934 		return 1;	/* Violator found */
1935 	    }
1936 	    break;
1937     }
1938     return 0;	/* Nothing found here, so keep going */
1939 }
1940 
1941 /*
1942  * ----------------------------------------------------------------------------
1943  *
1944  * cifCloseFunc --
1945  *
1946  * 	Called for each relevant tile during close operations.
1947  *
1948  * Results:
1949  *	Always returns 0 to keep the search alive.
1950  *
1951  * Side effects:
1952  *	Paints into cifNewPlane.  Tiles in old plane are tagged with
1953  *	a static value in ClientData, which does not need to be reset
1954  *	since the old plane will be free'd.
1955  * ----------------------------------------------------------------------------
1956  */
1957 
1958 #define CLOSE_SEARCH 0
1959 #define CLOSE_FILL   1
1960 #define CLOSE_DONE   2
1961 
1962 int
cifCloseFunc(tile,plane)1963 cifCloseFunc(tile, plane)
1964     Tile *tile;
1965     Plane *plane;
1966 {
1967     Rect area, newarea;
1968     int atotal;
1969     int cifGatherFunc();
1970 
1971     /* If tile is marked, then it has been handled, so ignore it */
1972     if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
1973 
1974     atotal = 0;
1975 
1976     /* Search all sides for connected space tiles, and accumulate the total */
1977     /* area.  If any connected tile borders infinity, then stop searching   */
1978     /* because the area is not enclosed.				    */
1979 
1980     cifGatherFunc(tile, &atotal, CLOSE_SEARCH);
1981 
1982     /* If the total area is smaller than the rule area, then paint all the  */
1983     /* tile areas into the destination plane.				    */
1984 
1985     if ((atotal != INFINITY) && (atotal < growDistance))
1986     {
1987 	cifGatherFunc(tile, &atotal, CLOSE_FILL);
1988     }
1989     else
1990     {
1991 	cifGatherFunc(tile, &atotal, CLOSE_DONE);
1992     }
1993 
1994     return 0;
1995 }
1996 
1997 int
cifGatherFunc(tile,atotal,mode)1998 cifGatherFunc(tile, atotal, mode)
1999     Tile *tile;
2000     int *atotal;
2001     bool mode;
2002 {
2003     Tile *tp;
2004     TileType type;
2005     dlong locarea;
2006     Rect area, newarea;
2007     ClientData cdata = (mode == CLOSE_SEARCH) ? (ClientData)CIF_UNPROCESSED :
2008 	    (ClientData)CIF_PENDING;
2009 
2010     static Stack *GatherStack = (Stack *)NULL;
2011 
2012     if (GatherStack == (Stack *)NULL)
2013 	GatherStack = StackNew(64);
2014 
2015     STACKPUSH(tile, GatherStack);
2016     while (!StackEmpty(GatherStack))
2017     {
2018 	tile = (Tile *)STACKPOP(GatherStack);
2019 
2020 	/* Ignore if tile has already been processed */
2021 	if (tile->ti_client != cdata) continue;
2022 
2023 	TiToRect(tile, &area);
2024 
2025 	/* Boundary tiles indicate an unclosed area, so set the area total to 	*/
2026 	/* INFINITY and don't try to run calculations on it.  NOTE:		*/
2027 	/* TiPlaneRect is slightly smaller than the plane boundaries on all	*/
2028 	/* sides.								*/
2029 
2030     	if ((area.r_xbot <= TiPlaneRect.r_xbot) ||
2031 		(area.r_ybot <= TiPlaneRect.r_ybot) ||
2032 	    	(area.r_xtop >= TiPlaneRect.r_xtop) ||
2033 		(area.r_ytop >= TiPlaneRect.r_ytop))
2034 	    *atotal = INFINITY;
2035 
2036     	/* Stop accumulating if already larger than growDistance to avoid the   */
2037     	/* possibility of integer overflow.					*/
2038     	if (mode == CLOSE_SEARCH)
2039     	{
2040 	    if ((*atotal != INFINITY) && (*atotal < growDistance))
2041 	    {
2042 	    	locarea = (dlong)(area.r_xtop - area.r_xbot)
2043 				* (dlong)(area.r_ytop - area.r_ybot);
2044 	        if (IsSplit(tile)) locarea /= 2;
2045 	        if (locarea > (dlong)INFINITY)
2046 		    *atotal = INFINITY;
2047 	        else
2048 		    *atotal += (int)locarea;
2049 	    }
2050         }
2051         else if (mode == CLOSE_FILL)
2052         {
2053 	    TileType dinfo = TiGetTypeExact(tile);
2054 
2055 	    /* The tile type cannot be depended on to have the TT_SIDE bit set	*/
2056 	    /* for the side of the tile that is TT_SPACE.  So set the side bit	*/
2057 	    /* manually.							*/
2058 
2059 	    if (IsSplit(tile))
2060 	    {
2061 	        if (TiGetLeftType(tile) == TT_SPACE)
2062 		    dinfo &= ~TT_SIDE;
2063 	        else
2064 		    dinfo |= TT_SIDE;
2065 	    }
2066 
2067 	    DBNMPaintPlane(cifPlane, dinfo, &area, CIFPaintTable, (PaintUndoInfo *)NULL);
2068 	    CIFTileOps++;
2069         }
2070 
2071         if (mode == CLOSE_SEARCH)
2072 	    tile->ti_client = (ClientData)CIF_PENDING;
2073         else
2074 	    tile->ti_client = (ClientData)CIF_PROCESSED;
2075 
2076         /* Look for additional neighboring space tiles */
2077         /* Check top */
2078         if (area.r_ytop != TiPlaneRect.r_ytop)
2079             for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
2080 	        if (tp->ti_client == cdata && TiGetBottomType(tp) == TT_SPACE)
2081 		{
2082 		    STACKPUSH(tp, GatherStack);
2083 		}
2084 
2085     	/* Check bottom */
2086     	if (area.r_ybot != TiPlaneRect.r_ybot)
2087             for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
2088 	    	if (tp->ti_client == cdata && TiGetTopType(tp) == TT_SPACE)
2089 		{
2090 		    STACKPUSH(tp, GatherStack);
2091 		}
2092 
2093     	/* Check left */
2094     	if (area.r_xbot != TiPlaneRect.r_xbot)
2095 	    for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
2096 	    	if (tp->ti_client == cdata && TiGetRightType(tp) == TT_SPACE)
2097 		{
2098 		    STACKPUSH(tp, GatherStack);
2099 		}
2100 
2101     	/* Check right */
2102     	if (area.r_xtop != TiPlaneRect.r_xtop)
2103 	    for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
2104 	    	if (tp->ti_client == cdata && TiGetLeftType(tp) == TT_SPACE)
2105 		{
2106 		    STACKPUSH(tp, GatherStack);
2107 		}
2108     }
2109     return 0;
2110 }
2111 
2112 /*--------------------------------------------------------------*/
2113 /* Support routines and definitions for cifSquaresFillArea	*/
2114 /*--------------------------------------------------------------*/
2115 
2116 /*------------------------------------------------------*/
2117 /* Data structure used for identifying contact strips	*/
2118 /*------------------------------------------------------*/
2119 
2120 typedef struct _linkedStrip {
2121     Rect	area;
2122     bool	vertical;	/* Tile is vertical */
2123     bool	shrink_ld;	/* Shrink left or down before creating cuts */
2124     bool	shrink_ur;	/* Shrink right or up before creating cuts */
2125     struct _linkedStrip *strip_next;
2126 } linkedStrip;
2127 
2128 typedef struct
2129 {
2130    int size;
2131    int pitch;
2132    linkedStrip *strips;
2133 } StripsData;
2134 
2135 /*
2136  *-------------------------------------------------------
2137  *
2138  * cifSquaresInitFunc --
2139  *
2140  *	Find the first unprocessed tile in the plane.
2141  *
2142  * Results:
2143  *	Return 1 to stop the search and process.
2144  *	Otherwise, return 0 to keep the search going.
2145  *
2146  *-------------------------------------------------------
2147  */
2148 
2149 int
cifSquaresInitFunc(tile,clientData)2150 cifSquaresInitFunc(tile, clientData)
2151     Tile *tile;
2152     ClientData clientData;
2153 {
2154     if (tile->ti_client == (ClientData) CIF_UNPROCESSED)
2155 	return 1;
2156     else
2157 	return 0;
2158 }
2159 
2160 /*
2161  *-------------------------------------------------------
2162  *
2163  * cifSquaresStripFunc --
2164  *
2165  *	Find vertical or horizontal strips of contact
2166  * material that is between 1 and 2 contact cuts wide.
2167  * Generate and return a list of all such strips.
2168  *
2169  * Results:  Return 0 to keep the search going.
2170  *
2171  *-------------------------------------------------------
2172  */
2173 
2174 int
cifSquaresStripFunc(tile,stripsData)2175 cifSquaresStripFunc(tile, stripsData)
2176     Tile *tile;
2177     StripsData *stripsData;
2178 {
2179     bool vertical;
2180     int width, height;
2181     linkedStrip *newStrip;
2182     Tile *tp, *tp2;
2183     Rect bbox;
2184 
2185     if (IsSplit(tile))
2186 	return 0;
2187     TiToRect(tile, &bbox);
2188 
2189     /* Check if the tile is wide enough for exactly one cut */
2190 
2191     width = bbox.r_xtop - bbox.r_xbot;
2192     height = bbox.r_ytop - bbox.r_ybot;
2193 
2194     if (height > width)
2195     {
2196 	vertical = TRUE;
2197 	height = width;
2198     }
2199     else
2200 	vertical = FALSE;
2201 
2202     if ((height < stripsData->size) || (height >=
2203 		(stripsData->size + stripsData->pitch)))
2204 	return 0;
2205 
2206     /* Ignore strips that are part of a larger	*/
2207     /* collection of non-manhattan geometry.	*/
2208 
2209     for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
2210 	if (IsSplit(tp))
2211 	    break;
2212     if (BOTTOM(tp) < TOP(tile))
2213 	return 0;
2214 
2215     /* Note that the max horizontal stripes rule guarantees	*/
2216     /* that a tile is always bounded on left and right by	*/
2217     /* TT_SPACE.  Thus, we only need to search the top and	*/
2218     /* bottom boundaries of horizontal tiles.			*/
2219 
2220     if (vertical)
2221     {
2222 	newStrip = (linkedStrip *)mallocMagic(sizeof(linkedStrip));
2223 	newStrip->area = bbox;
2224 	newStrip->vertical = TRUE;
2225 	newStrip->shrink_ur = (TTMaskHasType(&CIFSolidBits,
2226 		TiGetBottomType(RT(tile)))) ? TRUE : FALSE;
2227 	newStrip->shrink_ld = (TTMaskHasType(&CIFSolidBits,
2228 		TiGetTopType(LB(tile)))) ? TRUE : FALSE;
2229 	newStrip->strip_next = stripsData->strips;
2230 	stripsData->strips = newStrip;
2231     }
2232     else
2233     {
2234 	int segstart, segend;
2235 	int matchstart, matchend;
2236 
2237 	tp = RT(tile);
2238 	segend = RIGHT(tile);
2239 	while (RIGHT(tp) > LEFT(tile))
2240 	{
2241 	    /* Isolate segments of space along the top of the tile */
2242 
2243 	    while ((RIGHT(tp) > LEFT(tile)) &&
2244 			TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2245 		tp = BL(tp);
2246 	    segend = MIN(segend, RIGHT(tp));
2247 	    while ((RIGHT(tp) > LEFT(tile)) &&
2248 			TTMaskHasType(&DBSpaceBits, TiGetBottomType(tp)))
2249 		tp = BL(tp);
2250 	    segstart = MAX(LEFT(tile), RIGHT(tp));
2251 	    if (segend <= segstart) break;
2252 
2253 	    /* Find matching segments along the bottom of the  tile */
2254 
2255 	    for (tp2 = LB(tile); RIGHT(tp2) < segstart; tp2 = TR(tp2));
2256 
2257 	    while (LEFT(tp2) < segend)
2258 	    {
2259 		while (RIGHT(tp2) < segstart) tp2 = TR(tp2);
2260 		while ((LEFT(tp2) < segend) &&
2261 				TTMaskHasType(&CIFSolidBits, TiGetTopType(tp2)))
2262 		    tp2 = TR(tp2);
2263 		matchstart = MAX(LEFT(tp2), segstart);
2264 		while ((LEFT(tp2) < segend) &&
2265 				TTMaskHasType(&DBSpaceBits, TiGetTopType(tp2)))
2266 		    tp2 = TR(tp2);
2267 		matchend = MIN(LEFT(tp2), segend);
2268 		if (matchend <= matchstart) break;
2269 
2270 		/* Process the strip */
2271 
2272 		newStrip = (linkedStrip *)mallocMagic(sizeof(linkedStrip));
2273 		newStrip->area = bbox;
2274 		newStrip->area.r_xbot = matchstart;
2275 		newStrip->area.r_xtop = matchend;
2276 		newStrip->vertical = FALSE;
2277 		newStrip->strip_next = stripsData->strips;
2278 		newStrip->shrink_ur = (matchend != RIGHT(tile)) ? TRUE : FALSE;
2279 		newStrip->shrink_ld = (matchstart != LEFT(tile)) ? TRUE : FALSE;
2280 
2281 		stripsData->strips = newStrip;
2282 	    }
2283 	}
2284     }
2285     return 0;
2286 }
2287 
2288 /*
2289  *-------------------------------------------------------
2290  *
2291  * cifUnconnectFunc --
2292  *
2293  *	Find space tiles inside a possible contact area
2294  *
2295  * Results:	Return 1 to stop the ongoing search.
2296  *
2297  *-------------------------------------------------------
2298  */
2299 
2300 
2301 int
cifUnconnectFunc(tile,clientData)2302 cifUnconnectFunc(tile, clientData)
2303     Tile *tile;
2304     ClientData clientData;	/* unused */
2305 {
2306     TileType t = TiGetTypeExact(tile);
2307     if (t == TT_SPACE) return 1;
2308     else if (t & TT_DIAGONAL) return 1;
2309     else if (tile->ti_client != (ClientData)CIF_PROCESSED) return 1;
2310     return 0;
2311 }
2312 
2313 /*
2314  * ----------------------------------------------------------------------------
2315  *
2316  * cifRectBoundingBox --
2317  *
2318  * 	Fill regions of the current CIF plane with rectangles that represent
2319  *	the bounding box of each unconnected area.  This function "cleans
2320  *	up" areas processed by multiple rules and removes notches and
2321  *	cut-outs.
2322  *
2323  * Results:
2324  *	None.
2325  *
2326  * Side effects:
2327  *
2328  * ----------------------------------------------------------------------------
2329  */
2330 
2331 void
cifRectBoundingBox(op,cellDef,plane)2332 cifRectBoundingBox(op, cellDef, plane)
2333     CIFOp *op;
2334     CellDef *cellDef;
2335     Plane *plane;
2336 {
2337     Tile *tile = NULL, *t, *tp;
2338     Rect bbox, area, *maxr;
2339     int i, j, savecount;
2340     TileType type;
2341     bool simple;
2342     static Stack *BoxStack = (Stack *)NULL;
2343 
2344     if (BoxStack == (Stack *)NULL)
2345 	BoxStack = StackNew(64);
2346 
2347     while (DBSrPaintArea((Tile *)tile, plane, &TiPlaneRect, &CIFSolidBits,
2348 		cifSquaresInitFunc, (ClientData)NULL) != 0)
2349     {
2350 	/* Now, search for (nontrivially) connected tiles in all	*/
2351 	/* directions.  Mark the tiles, and record the bounding box.	*/
2352 	/* (Largely copied from cifSquaresFillArea)			*/
2353 
2354 	simple = TRUE;
2355 	tile = plane->pl_hint;
2356 	TiToRect(tile, &bbox);
2357 
2358 	PUSHTILE(tile, BoxStack);
2359 	while (!StackEmpty(BoxStack))
2360 	{
2361 	    t = (Tile *) STACKPOP(BoxStack);
2362 	    if (t->ti_client != (ClientData)CIF_PENDING) continue;
2363             t->ti_client = (ClientData)CIF_PROCESSED;
2364 
2365 	    /* Adjust bounding box */
2366 	    TiToRect(t, &area);
2367 	    GeoInclude(&area, &bbox);
2368 
2369 	    if (IsSplit(t)) simple = FALSE;
2370 
2371 	    /* Top */
2372 	    for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2373 		if (TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2374 		{
2375 		    simple = FALSE;
2376 		    PUSHTILE(tp, BoxStack);
2377 		}
2378 
2379 	    /* Left */
2380 	    for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2381 		if (TTMaskHasType(&CIFSolidBits, TiGetRightType(tp)))
2382 		{
2383 		    simple = FALSE;
2384 		    PUSHTILE(tp, BoxStack);
2385 		}
2386 
2387 	    /* Bottom */
2388 	    for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2389 		if (TTMaskHasType(&CIFSolidBits, TiGetTopType(tp)))
2390 		{
2391 		    simple = FALSE;
2392 		    PUSHTILE(tp, BoxStack);
2393 		}
2394 
2395 	    /* Right */
2396 	    for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2397 		if (TTMaskHasType(&CIFSolidBits, TiGetLeftType(tp)))
2398 		{
2399 		    simple = FALSE;
2400 		    PUSHTILE(tp, BoxStack);
2401 		}
2402 	}
2403 
2404 	if (op->co_client == (ClientData)1)	/* external */
2405 	{
2406 	    DBPaintPlane(cifPlane, &bbox, CIFPaintTable, (PaintUndoInfo *)NULL);
2407 	    CIFTileOps++;
2408 	}
2409 	else	/* internal */
2410 	{
2411 	    if (simple)
2412 	    {
2413 		DBPaintPlane(cifPlane, &bbox, CIFPaintTable, (PaintUndoInfo *)NULL);
2414 		CIFTileOps++;
2415 	    }
2416 	    else
2417 	    {
2418 		maxr = FindMaxRectangle2(&bbox, tile, plane, NULL);
2419 		DBPaintPlane(cifPlane, maxr, CIFPaintTable, (PaintUndoInfo *)NULL);
2420 		CIFTileOps++;
2421 	    }
2422 	}
2423 
2424 	/* Clear the tiles that were processed in this set */
2425 
2426 	tile->ti_client = (ClientData)CIF_IGNORE;
2427 	STACKPUSH(tile, BoxStack);
2428 	while (!StackEmpty(BoxStack))
2429 	{
2430 	    t = (Tile *) STACKPOP(BoxStack);
2431 
2432 	    /* Top */
2433 	    for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2434 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2435 		{
2436 		    tp->ti_client = (ClientData)CIF_IGNORE;
2437 		    STACKPUSH(tp, BoxStack);
2438 		}
2439 
2440 	    /* Left */
2441 	    for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2442 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2443 		{
2444 		    tp->ti_client = (ClientData)CIF_IGNORE;
2445 		    STACKPUSH(tp, BoxStack);
2446 		}
2447 
2448 	    /* Bottom */
2449 	    for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2450 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2451 		{
2452 		    tp->ti_client = (ClientData)CIF_IGNORE;
2453 		    STACKPUSH(tp, BoxStack);
2454 		}
2455 
2456 	    /* Right */
2457 	    for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2458 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2459 		{
2460 		    tp->ti_client = (ClientData)CIF_IGNORE;
2461 		    STACKPUSH(tp, BoxStack);
2462 		}
2463 	}
2464     }
2465 }
2466 
2467 /*
2468  * ----------------------------------------------------------------------------
2469  *
2470  * cifSquaresFillArea --
2471  *
2472  *	Fill areas in the current CIF output plane with contact cuts based on
2473  *	the SQUARES operation passed in "op".  This differs from the original
2474  *	tile-based contact cut generation by collecting all connected tiles
2475  *	in an area, and placing cuts relative to that area's bounding box.
2476  *	A tile search is used to select the parts of any non-rectangular area
2477  *	inside the bounding box that allow contact cuts, which lets cuts
2478  *	be placed across tile boundaries and inside non-manhattan tiles.
2479  *	It also allows contacts to be placed inside complex structures such
2480  *	as (possibly intersecting) guardrings.
2481  *
2482  * Results:
2483  *	None.
2484  *
2485  * Side effects:
2486  *
2487  * ----------------------------------------------------------------------------
2488  */
2489 
2490 void
cifSquaresFillArea(op,cellDef,plane)2491 cifSquaresFillArea(op, cellDef, plane)
2492     CIFOp *op;
2493     CellDef *cellDef;
2494     Plane *plane;
2495 {
2496     Tile *tile, *t, *tp;
2497     Rect bbox, area, square, cut, llcut;
2498     int nAcross, nUp, left, pitch, size, diff, right;
2499     int i, j, k, savecount;
2500     TileType type;
2501     SquaresData *squares = (SquaresData *)op->co_client;
2502     StripsData stripsData;
2503     linkedStrip *stripList;
2504     bool simple;
2505     static Stack *CutStack = (Stack *)NULL;
2506 
2507     pitch = squares->sq_size + squares->sq_sep;
2508     size = squares->sq_size + 2 * squares->sq_border;
2509     diff = squares->sq_sep - 2 * squares->sq_border;
2510 
2511     if (CutStack == (Stack *)NULL)
2512 	CutStack = StackNew(64);
2513 
2514     /* Two-pass algorithm */
2515 
2516     /* Search the plane for "strips", sections of contact that are only	*/
2517     /* wide enough for 1 cut.  Process them separately, then erase the	*/
2518     /* processed areas.	  The purpose of this is to avoid applying the	*/
2519     /* contact matrix algorithm on non-convex spaces, such as guard	*/
2520     /* rings, where centering the matrix on the bounding box of the	*/
2521     /* contact area may produce a matrix misaligned with the contact	*/
2522     /* strips, preventing any contacts from being drawn!  Due to the	*/
2523     /* maximum horizontal stripes rule for corner stitched tiles, we	*/
2524     /* need only identify vertical contact strips.  After processing	*/
2525     /* and erasing them, all remaining areas will be convex.  This	*/
2526     /* algorithm allows contacts to be drawn in any arbitrary geometry.	*/
2527 
2528     stripsData.size = size;
2529     stripsData.pitch = pitch;
2530     stripsData.strips = NULL;
2531     DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2532 		cifSquaresStripFunc, (ClientData)&stripsData);
2533 
2534     /* Generate cuts in each strip found, then erase the strip */
2535 
2536     stripList = stripsData.strips;
2537     while (stripList != NULL)
2538     {
2539 	Rect stripLess = stripList->area;
2540 
2541 	if (diff > 0)
2542 	{
2543 	    if (stripList->vertical)
2544 	    {
2545 		if (stripList->shrink_ur) stripLess.r_ytop -= diff;
2546 		if (stripList->shrink_ld) stripLess.r_ybot += diff;
2547 	    }
2548 	    else
2549 	    {
2550 		if (stripList->shrink_ur) stripLess.r_xtop -= diff;
2551 		if (stripList->shrink_ld) stripLess.r_xbot += diff;
2552 	    }
2553 	}
2554 
2555 	/* Create the cuts */
2556 
2557 	if (op->co_opcode == CIFOP_SQUARES)
2558 	    cifSquareFunc(&stripLess, op, &nUp, &nAcross, &llcut);
2559 	else if (op->co_opcode == CIFOP_SQUARES_G)
2560 	    cifSquareGridFunc(&stripLess, op, &nUp, &nAcross, &llcut);
2561 
2562 	cut.r_ybot = llcut.r_ybot;
2563 	cut.r_ytop = llcut.r_ytop;
2564 
2565 	for (i = 0; i < nUp; i++)
2566 	{
2567 	    cut.r_xbot = llcut.r_xbot;
2568 	    cut.r_xtop = llcut.r_xtop;
2569 	    for (j = 0; j < nAcross; j++)
2570 	    {
2571 		DBPaintPlane(cifPlane, &cut, CIFPaintTable, (PaintUndoInfo *)NULL);
2572 		cut.r_xbot += pitch;
2573 		cut.r_xtop += pitch;
2574 	    }
2575 	    cut.r_ybot += pitch;
2576 	    cut.r_ytop += pitch;
2577 	}
2578 	if (nUp == 0)
2579 	{
2580 	    if (stripList->shrink_ur == 0 && stripList->shrink_ld == 0)
2581 	    {
2582 		/* The following code is backwardly-compatible with the	 */
2583 		/* original behavior of allowing cuts that do not have	 */
2584 		/* sufficient border.  Here, we restrict that to contact */
2585 		/* areas exactly matching the cut size.  There should be */
2586 		/* a flag to allow contacts to be generated this way.	 */
2587 
2588 		if ((stripList->area.r_xtop - stripList->area.r_xbot
2589 			== squares->sq_size) && (stripList->area.r_ytop
2590 			- stripList->area.r_ybot == squares->sq_size))
2591 		{
2592 		    DBPaintPlane(cifPlane, &stripList->area, CIFPaintTable,
2593 				(PaintUndoInfo *)NULL);
2594 		    CIFTileOps++;
2595 		}
2596 		else
2597 		    CIFError(&stripList->area, "no room for contact cuts in area!");
2598 	    }
2599 
2600 	    /* Ad hoc rule catches problems due to contact areas of the proper	*/
2601 	    /* size not fitting cuts because the grid offset prohibits it.	*/
2602 	    else if (((stripList->area.r_ur.p_x - stripList->area.r_ll.p_x) *
2603 			(stripList->area.r_ur.p_y - stripList->area.r_ll.p_y)) >
2604 			2 * (pitch * pitch))
2605 		CIFError(&stripList->area, "contact strip with no room for cuts!");
2606 	}
2607 
2608 	DBPaintPlane(plane, &stripList->area, CIFEraseTable,
2609 		(PaintUndoInfo *) NULL);
2610 	freeMagic(stripList);
2611 	stripList = stripList->strip_next;
2612     }
2613 
2614     /* 2nd pass:  Search the plane for unmarked tiles */
2615 
2616     while (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2617 		cifSquaresInitFunc, (ClientData)NULL) != 0)
2618     {
2619 	/* Now, search for (nontrivially) connected tiles in all	*/
2620 	/* directions.  Mark the tiles, and record the bounding box.	*/
2621 	/* (Largely copied from cifBloatAllFunc)			*/
2622 
2623 	simple = TRUE;
2624 	tile = plane->pl_hint;
2625 	TiToRect(tile, &bbox);
2626 
2627 	PUSHTILE(tile, CutStack);
2628 	while (!StackEmpty(CutStack))
2629 	{
2630 	    t = (Tile *) STACKPOP(CutStack);
2631 	    if (t->ti_client != (ClientData)CIF_PENDING) continue;
2632             t->ti_client = (ClientData)CIF_PROCESSED;
2633 
2634 	    /* Adjust bounding box */
2635 	    TiToRect(t, &area);
2636 	    GeoInclude(&area, &bbox);
2637 
2638 	    if (IsSplit(t)) simple = FALSE;
2639 
2640 	    /* Top */
2641 	    for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2642 		if (TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2643 		{
2644 		    simple = FALSE;
2645 		    PUSHTILE(tp, CutStack);
2646 		}
2647 
2648 	    /* Left */
2649 	    for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2650 		if (TTMaskHasType(&CIFSolidBits, TiGetRightType(tp)))
2651 		{
2652 		    simple = FALSE;
2653 		    PUSHTILE(tp, CutStack);
2654 		}
2655 
2656 	    /* Bottom */
2657 	    for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2658 		if (TTMaskHasType(&CIFSolidBits, TiGetTopType(tp)))
2659 		{
2660 		    simple = FALSE;
2661 		    PUSHTILE(tp, CutStack);
2662 		}
2663 
2664 	    /* Right */
2665 	    for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2666 		if (TTMaskHasType(&CIFSolidBits, TiGetLeftType(tp)))
2667 		{
2668 		    simple = FALSE;
2669 		    PUSHTILE(tp, CutStack);
2670 		}
2671 	}
2672 
2673 	savecount = CIFTileOps;
2674 
2675 	for (k = 0; k < 3; k++)	/* prepare for up to 3 passes */
2676 	{
2677 	    /* Determine the contact cut offsets from the bounding box */
2678 
2679 	    if (op->co_opcode == CIFOP_SQUARES)
2680 		cifSquareFunc(&bbox, op, &nUp, &nAcross, &llcut);
2681 	    else if (op->co_opcode == CIFOP_SQUARES_G)
2682 		cifSquareGridFunc(&bbox, op, &nUp, &nAcross, &llcut);
2683 
2684 	    cut.r_ybot = llcut.r_ybot;
2685 	    cut.r_ytop = llcut.r_ytop;
2686 
2687 	    /* For each contact cut area, check that there is	*/
2688 	    /* no whitespace					*/
2689 
2690 	    for (i = 0; i < nUp; i++)
2691 	    {
2692 		cut.r_xbot = llcut.r_xbot;
2693 		cut.r_xtop = llcut.r_xtop;
2694 
2695 		square.r_ybot = cut.r_ybot - squares->sq_border;
2696 		square.r_ytop = cut.r_ytop + squares->sq_border;
2697 
2698 		for (j = 0; j < nAcross; j++)
2699 		{
2700 		    square.r_xbot = cut.r_xbot - squares->sq_border;
2701 		    square.r_xtop = cut.r_xtop + squares->sq_border;
2702 
2703     		    /* If there is only one simple rectangle in the	*/
2704 		    /* area, the area is convex, so we don't have to	*/
2705 		    /* check for unconnected regions.			*/
2706 
2707 		    if (simple || DBSrPaintArea((Tile *)tile, plane, &square,
2708 				&DBAllTypeBits, cifUnconnectFunc,
2709 				(ClientData)NULL) == 0)
2710 		    {
2711 			DBPaintPlane(cifPlane, &cut, CIFPaintTable,
2712 				(PaintUndoInfo *)NULL);
2713 			CIFTileOps++;
2714 		    }
2715 		    cut.r_xbot += pitch;
2716 		    cut.r_xtop += pitch;
2717 		}
2718 		cut.r_ybot += pitch;
2719 		cut.r_ytop += pitch;
2720 	    }
2721 	    if (savecount != CIFTileOps) break;
2722 
2723 	    /* In non-Manhattan regions with beveled corners, where	*/
2724 	    /* the bounding box has space for 2 contacts, there may not	*/
2725 	    /* be space in the shape itself for more than one.  We will	*/
2726 	    /* attempt to shrink X, Y, and/or both to fit (up to 3	*/
2727 	    /* passes may be necessary).				*/
2728 
2729 	    if (nUp == 2)
2730 	    {
2731 		int bdiff = 1 + (bbox.r_ytop - bbox.r_ybot) -
2732 			(2 * (squares->sq_size + squares->sq_border) +
2733 			squares->sq_sep);
2734 		if (bdiff & 0x1) bdiff++;	/* bdiff must be even	*/
2735 		bdiff >>= 1;			/* take half		*/
2736 		bbox.r_ytop -= bdiff;
2737 		bbox.r_ybot += bdiff;
2738 	    }
2739 	    else if (nAcross == 2)
2740 	    {
2741 		int bdiff = 1 + (bbox.r_xtop - bbox.r_xbot) -
2742 			(2 * (squares->sq_size + squares->sq_border) +
2743 			squares->sq_sep);
2744 		if (bdiff & 0x1) bdiff++;	/* bdiff must be even	*/
2745 		bdiff >>= 1;			/* take half		*/
2746 		bbox.r_xtop -= bdiff;
2747 		bbox.r_xbot += bdiff;
2748 	    }
2749 	    else
2750 		break;
2751 	}
2752 	if (savecount == CIFTileOps)
2753 	    CIFError(&bbox, "no room for contacts in area!");
2754 
2755 	/* Clear the tiles that were processed */
2756 
2757 	tile->ti_client = (ClientData)CIF_IGNORE;
2758 	STACKPUSH(tile, CutStack);
2759 	while (!StackEmpty(CutStack))
2760 	{
2761 	    t = (Tile *) STACKPOP(CutStack);
2762 
2763 	    /* Top */
2764 	    for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2765 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2766 		{
2767 		    tp->ti_client = (ClientData)CIF_IGNORE;
2768 		    STACKPUSH(tp, CutStack);
2769 		}
2770 
2771 	    /* Left */
2772 	    for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2773 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2774 		{
2775 		    tp->ti_client = (ClientData)CIF_IGNORE;
2776 		    STACKPUSH(tp, CutStack);
2777 		}
2778 
2779 	    /* Bottom */
2780 	    for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2781 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2782 		{
2783 		    tp->ti_client = (ClientData)CIF_IGNORE;
2784 		    STACKPUSH(tp, CutStack);
2785 		}
2786 
2787 	    /* Right */
2788 	    for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2789 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
2790 		{
2791 		    tp->ti_client = (ClientData)CIF_IGNORE;
2792 		    STACKPUSH(tp, CutStack);
2793 		}
2794 	}
2795     }
2796 
2797     /* Clear all the tiles that were processed */
2798     DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2799 		cifProcessResetFunc, (ClientData)NULL);
2800 }
2801 
2802 /*
2803  * ----------------------------------------------------------------------------
2804  *
2805  * cifSlotsFillArea --
2806  *
2807  *	Fill areas in the current CIF output plane with contact cuts based on
2808  *	the SLOTS operation passed in "op".  This routine is like
2809  *	cifSquaresFillArea but handles X and Y dimensions independently.
2810  *
2811  * Results:
2812  *	None.
2813  *
2814  * Side effects:
2815  *
2816  * ----------------------------------------------------------------------------
2817  */
2818 
2819 void
cifSlotsFillArea(op,cellDef,plane)2820 cifSlotsFillArea(op, cellDef, plane)
2821     CIFOp *op;
2822     CellDef *cellDef;
2823     Plane *plane;
2824 {
2825     Tile *tile, *t, *tp;
2826     Rect bbox, area, square, cut, llcut;
2827     int nAcross, nUp, left, spitch, lpitch, ssize, lsize, offset;
2828     int diff, right;
2829     int xpitch, ypitch, xborder, yborder, xdiff, ydiff;
2830     int i, j, k, savecount;
2831     TileType type;
2832     SlotsData *slots = (SlotsData *)op->co_client;
2833     StripsData stripsData;
2834     linkedStrip *stripList;
2835     bool simple, vertical;
2836     static Stack *CutStack = (Stack *)NULL;
2837 
2838     spitch = slots->sl_ssize + slots->sl_ssep;
2839     lpitch = slots->sl_lsize + slots->sl_lsep;
2840     ssize = slots->sl_ssize + 2 * slots->sl_sborder;
2841     lsize = slots->sl_lsize + 2 * slots->sl_lborder;
2842 
2843     /* This may not be good in all cases!  Amount to shorten a strip	*/
2844     /* depends on the orientation of the cuts on either side of the	*/
2845     /* connected strip edge. . .					*/
2846     diff = slots->sl_lsep - slots->sl_lborder - slots->sl_sborder;
2847 
2848     if (CutStack == (Stack *)NULL)
2849 	CutStack = StackNew(64);
2850 
2851     /* Two-pass algorithm */
2852 
2853     /* Search the plane for "strips", sections of contact that are only	*/
2854     /* wide enough for 1 cut.  Process them separately, then erase the	*/
2855     /* processed areas.	  The purpose of this is to avoid applying the	*/
2856     /* contact matrix algorithm on non-convex spaces, such as guard	*/
2857     /* rings, where centering the matrix on the bounding box of the	*/
2858     /* contact area may produce a matrix misaligned with the contact	*/
2859     /* strips, preventing any contacts from being drawn!  Due to the	*/
2860     /* maximum horizontal stripes rule for corner stitched tiles, we	*/
2861     /* need only identify vertical contact strips.  After processing	*/
2862     /* and erasing them, all remaining areas will be convex.  This	*/
2863     /* algorithm allows contacts to be drawn in any arbitrary geometry.	*/
2864 
2865     stripsData.size = ssize;
2866     stripsData.pitch = spitch;
2867     stripsData.strips = NULL;
2868     DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2869 		cifSquaresStripFunc, (ClientData)&stripsData);
2870 
2871     /* Generate cuts in each strip found, then erase the strip */
2872 
2873     stripList = stripsData.strips;
2874     while (stripList != NULL)
2875     {
2876 	Rect stripLess = stripList->area;
2877 
2878 	if (diff > 0)
2879 	{
2880 	    if (stripList->vertical)
2881 	    {
2882 		if (stripList->shrink_ur) stripLess.r_ytop -= diff;
2883 		if (stripList->shrink_ld) stripLess.r_ybot += diff;
2884 	    }
2885 	    else
2886 	    {
2887 		if (stripList->shrink_ur) stripLess.r_xtop -= diff;
2888 		if (stripList->shrink_ld) stripLess.r_xbot += diff;
2889 	    }
2890 	}
2891 
2892 	/* Create the cuts */
2893 
2894 	cifSlotFunc(&stripLess, op, &nUp, &nAcross, &llcut, stripList->vertical);
2895 
2896 	cut = llcut;
2897 
2898 	if (stripList->vertical)
2899 	{
2900 	    for (i = 0; i < nUp; i++)
2901 	    {
2902 		DBPaintPlane(cifPlane, &cut, CIFPaintTable, (PaintUndoInfo *)NULL);
2903 		cut.r_ybot += lpitch;
2904 		cut.r_ytop += lpitch;
2905 	    }
2906 	}
2907 	else
2908 	{
2909 	    for (i = 0; i < nAcross; i++)
2910 	    {
2911 		DBPaintPlane(cifPlane, &cut, CIFPaintTable, (PaintUndoInfo *)NULL);
2912 		cut.r_xbot += lpitch;
2913 		cut.r_xtop += lpitch;
2914 	    }
2915 	}
2916 
2917 	if (nUp == 0 || nAcross == 0)
2918 	{
2919 	    if (stripList->shrink_ur == 0 && stripList->shrink_ld == 0)
2920 	    {
2921 		/* The following code is backwardly-compatible with the	 */
2922 		/* original behavior of allowing cuts that do not have	 */
2923 		/* sufficient border.  Here, we restrict that to contact */
2924 		/* areas exactly matching the cut size.  There should be */
2925 		/* a flag to allow contacts to be generated this way.	 */
2926 
2927 		if (((stripList->area.r_xtop - stripList->area.r_xbot
2928 			== slots->sl_ssize) && (stripList->area.r_ytop
2929 			- stripList->area.r_ybot == slots->sl_lsize)) ||
2930 			((stripList->area.r_xtop - stripList->area.r_xbot
2931 			== slots->sl_lsize) && (stripList->area.r_ytop
2932 			- stripList->area.r_ybot == slots->sl_ssize)))
2933 		{
2934 		    DBPaintPlane(cifPlane, &stripList->area, CIFPaintTable,
2935 				(PaintUndoInfo *)NULL);
2936 		    CIFTileOps++;
2937 		}
2938 		else
2939 		    CIFError(&stripList->area, "no room for contact cuts in area!");
2940 	    }
2941 
2942 	    /* Ad hoc rule catches problems due to contact areas of the proper	*/
2943 	    /* size not fitting cuts because the grid offset prohibits it.	*/
2944 	    else if (((stripList->area.r_ur.p_x - stripList->area.r_ll.p_x) *
2945 			(stripList->area.r_ur.p_y - stripList->area.r_ll.p_y)) >
2946 			2 * (lpitch * spitch))
2947 		CIFError(&stripList->area, "contact strip with no room for cuts!");
2948 	}
2949 
2950 	DBPaintPlane(plane, &stripList->area, CIFEraseTable,
2951 		(PaintUndoInfo *) NULL);
2952 	freeMagic(stripList);
2953 	stripList = stripList->strip_next;
2954     }
2955 
2956     /* 2nd pass:  Search the plane for unmarked tiles */
2957 
2958     while (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2959 		cifSquaresInitFunc, (ClientData)NULL) != 0)
2960     {
2961 	/* Now, search for (nontrivially) connected tiles in all	*/
2962 	/* directions.  Mark the tiles, and record the bounding box.	*/
2963 	/* (Largely copied from cifBloatAllFunc)			*/
2964 
2965 	simple = TRUE;
2966 	tile = plane->pl_hint;
2967 	TiToRect(tile, &bbox);
2968 
2969 	PUSHTILE(tile, CutStack);
2970 	while (!StackEmpty(CutStack))
2971 	{
2972 	    t = (Tile *) STACKPOP(CutStack);
2973 	    if (t->ti_client != (ClientData)CIF_PENDING) continue;
2974             t->ti_client = (ClientData)CIF_PROCESSED;
2975 
2976 	    /* Adjust bounding box */
2977 	    TiToRect(t, &area);
2978 	    GeoInclude(&area, &bbox);
2979 
2980 	    if (IsSplit(t)) simple = FALSE;
2981 
2982 	    /* Top */
2983 	    for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2984 		if (TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2985 		{
2986 		    simple = FALSE;
2987 		    PUSHTILE(tp, CutStack);
2988 		}
2989 
2990 	    /* Left */
2991 	    for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2992 		if (TTMaskHasType(&CIFSolidBits, TiGetRightType(tp)))
2993 		{
2994 		    simple = FALSE;
2995 		    PUSHTILE(tp, CutStack);
2996 		}
2997 
2998 	    /* Bottom */
2999 	    for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
3000 		if (TTMaskHasType(&CIFSolidBits, TiGetTopType(tp)))
3001 		{
3002 		    simple = FALSE;
3003 		    PUSHTILE(tp, CutStack);
3004 		}
3005 
3006 	    /* Right */
3007 	    for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
3008 		if (TTMaskHasType(&CIFSolidBits, TiGetLeftType(tp)))
3009 		{
3010 		    simple = FALSE;
3011 		    PUSHTILE(tp, CutStack);
3012 		}
3013 	}
3014 
3015 	/* May want to attempt a second pass with the orthogonal alignment? */
3016 	if ((bbox.r_xtop - bbox.r_xbot) > (bbox.r_ytop - bbox.r_ybot))
3017 	    vertical = FALSE;
3018 	else
3019 	    vertical = TRUE;
3020 
3021 	if (vertical)
3022 	{
3023 	    xpitch = spitch;
3024 	    ypitch = lpitch;
3025 	    xborder = slots->sl_sborder;
3026 	    yborder = slots->sl_lborder;
3027 	    xdiff = 2 * (slots->sl_ssize + slots->sl_sborder) + slots->sl_ssep;
3028 	    ydiff = 2 * (slots->sl_lsize + slots->sl_lborder) + slots->sl_lsep;
3029 	}
3030 	else
3031 	{
3032 	    xpitch = lpitch;
3033 	    ypitch = spitch;
3034 	    xborder = slots->sl_lborder;
3035 	    yborder = slots->sl_sborder;
3036 	    xdiff = 2 * (slots->sl_lsize + slots->sl_lborder) + slots->sl_lsep;
3037 	    ydiff = 2 * (slots->sl_ssize + slots->sl_sborder) + slots->sl_ssep;
3038 	}
3039 
3040 	savecount = CIFTileOps;
3041 
3042 	for (k = 0; k < 3; k++)	/* prepare for up to 3 passes */
3043 	{
3044 	    /* Determine the contact cut offsets from the bounding box */
3045 
3046 	    cifSlotFunc(&bbox, op, &nUp, &nAcross, &llcut, vertical);
3047 
3048 	    cut.r_ybot = llcut.r_ybot + slots->sl_start;
3049 	    cut.r_ytop = llcut.r_ytop + slots->sl_start;
3050 
3051 	    /* For each contact cut area, check that there is	*/
3052 	    /* no whitespace					*/
3053 
3054 	    offset = slots->sl_start;
3055 	    for (i = 0; i < nUp; i++)
3056 	    {
3057 		cut.r_xbot = llcut.r_xbot + offset;
3058 		cut.r_xtop = llcut.r_xtop + offset;
3059 
3060 		square.r_ybot = cut.r_ybot - yborder;
3061 		square.r_ytop = cut.r_ytop + yborder;
3062 
3063 		for (j = 0; j < nAcross; j++)
3064 		{
3065 		    square.r_xbot = cut.r_xbot - xborder;
3066 		    square.r_xtop = cut.r_xtop + xborder;
3067 
3068     		    /* If there is only one simple rectangle in the	*/
3069 		    /* area, the area is convex, so we don't have to	*/
3070 		    /* check for unconnected regions.			*/
3071 
3072 		    if (simple || DBSrPaintArea((Tile *)tile, plane, &square,
3073 				&DBAllTypeBits, cifUnconnectFunc,
3074 				(ClientData)NULL) == 0)
3075 		    {
3076 			DBPaintPlane(cifPlane, &cut, CIFPaintTable,
3077 				(PaintUndoInfo *)NULL);
3078 			CIFTileOps++;
3079 		    }
3080 		    cut.r_xbot += xpitch;
3081 		    cut.r_xtop += xpitch;
3082 		}
3083 		cut.r_ybot += ypitch;
3084 		cut.r_ytop += ypitch;
3085 		offset += slots->sl_offset;
3086 		if (offset >= xpitch) offset -= xpitch;
3087 	    }
3088 	    if (savecount != CIFTileOps) break;
3089 
3090 	    /* In non-Manhattan regions with beveled corners, where	*/
3091 	    /* the bounding box has space for 2 contacts, there may not	*/
3092 	    /* be space in the shape itself for more than one.  We will	*/
3093 	    /* attempt to shrink X, Y, and/or both to fit (up to 3	*/
3094 	    /* passes may be necessary).				*/
3095 
3096 	    if (nUp == 2)
3097 	    {
3098 		int bdiff = 1 + (bbox.r_ytop - bbox.r_ybot) - ydiff;
3099 		if (bdiff & 0x1) bdiff++;	/* bdiff must be even	*/
3100 		bdiff >>= 1;			/* take half		*/
3101 		bbox.r_ytop -= bdiff;
3102 		bbox.r_ybot += bdiff;
3103 	    }
3104 	    else if (nAcross == 2)
3105 	    {
3106 		int bdiff = 1 + (bbox.r_xtop - bbox.r_xbot) - xdiff;
3107 		if (bdiff & 0x1) bdiff++;	/* bdiff must be even	*/
3108 		bdiff >>= 1;			/* take half		*/
3109 		bbox.r_xtop -= bdiff;
3110 		bbox.r_xbot += bdiff;
3111 	    }
3112 	    else
3113 		break;
3114 	}
3115 	if (savecount == CIFTileOps)
3116 	    CIFError(&bbox, "no room for contacts in area!");
3117 
3118 	/* Clear the tiles that were processed */
3119 
3120 	tile->ti_client = (ClientData)CIF_IGNORE;
3121 	STACKPUSH(tile, CutStack);
3122 	while (!StackEmpty(CutStack))
3123 	{
3124 	    t = (Tile *) STACKPOP(CutStack);
3125 
3126 	    /* Top */
3127 	    for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
3128 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
3129 		{
3130 		    tp->ti_client = (ClientData)CIF_IGNORE;
3131 		    STACKPUSH(tp, CutStack);
3132 		}
3133 
3134 	    /* Left */
3135 	    for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
3136 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
3137 		{
3138 		    tp->ti_client = (ClientData)CIF_IGNORE;
3139 		    STACKPUSH(tp, CutStack);
3140 		}
3141 
3142 	    /* Bottom */
3143 	    for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
3144 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
3145 		{
3146 		    tp->ti_client = (ClientData)CIF_IGNORE;
3147 		    STACKPUSH(tp, CutStack);
3148 		}
3149 
3150 	    /* Right */
3151 	    for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
3152 		if (tp->ti_client == (ClientData)CIF_PROCESSED)
3153 		{
3154 		    tp->ti_client = (ClientData)CIF_IGNORE;
3155 		    STACKPUSH(tp, CutStack);
3156 		}
3157 	}
3158     }
3159 
3160     /* Clear all the tiles that were processed */
3161     DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
3162 		cifProcessResetFunc, (ClientData)NULL);
3163 }
3164 
3165 /*
3166  * ----------------------------------------------------------------------------
3167  *
3168  * cifBloatMaxFunc --
3169  *
3170  * 	Called once for each tile to be selectively bloated or
3171  *	shrunk using the CIFOP_BLOATMAX or CIFOP_BLOATMIN operation.
3172  *
3173  * Results:
3174  *	Always returns 0 to keep the search alive.
3175  *
3176  * Side effects:
3177  *	Uses the bloat table in the current CIFOp to expand or shrink
3178  *	the tile, depending on which tiles it abuts.  The rectangular
3179  *	area of the tile is modified by moving each side in or out
3180  *	by the maximum bloat distance for any of its neighbors on
3181  *	that side.  The result is a new rectangle, which is OR'ed
3182  *	into the result plane.  Note:  any edge between two tiles of
3183  *	same type is given a zero bloat factor.
3184  *
3185  * ----------------------------------------------------------------------------
3186  */
3187 
3188 int
cifBloatMaxFunc(tile,op)3189 cifBloatMaxFunc(tile, op)
3190     Tile *tile;			/* The tile to be processed. */
3191     CIFOp *op;			/* Describes the operation to be performed
3192 				 * (all we care about is the opcode and
3193 				 * bloat table).
3194 				 */
3195 {
3196     Rect area;
3197     int bloat, tmp;
3198     Tile *t;
3199     TileType type, otherType;
3200     BloatData *bloats = (BloatData *)op->co_client;
3201 
3202     /* Get the tile into CIF coordinates. */
3203 
3204     type = TiGetType(tile);
3205     TiToRect(tile, &area);
3206     area.r_xbot *= cifScale;
3207     area.r_ybot *= cifScale;
3208     area.r_xtop *= cifScale;
3209     area.r_ytop *= cifScale;
3210 
3211     /* See how much to adjust the left side of the tile. */
3212 
3213     if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3214     else bloat = 10000000;
3215     for (t = BL(tile); BOTTOM(t) < TOP(tile); t = RT(t))
3216     {
3217 	otherType = TiGetType(t);
3218 	if (otherType == type) continue;
3219 	tmp = bloats->bl_distance[otherType];
3220 	if (op->co_opcode == CIFOP_BLOATMAX)
3221 	{
3222 	    if (tmp > bloat) bloat = tmp;
3223 	}
3224 	else if (tmp < bloat) bloat = tmp;
3225     }
3226     if ((bloat < 10000000) && (bloat > -10000000))
3227 	area.r_xbot -= bloat;
3228 
3229     /* Now figure out how much to adjust the top side of the tile. */
3230 
3231     if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3232     else bloat = 10000000;
3233     for (t = RT(tile); RIGHT(t) > LEFT(tile); t = BL(t))
3234     {
3235 	otherType = TiGetType(t);
3236 	if (otherType == type) continue;
3237 	tmp = bloats->bl_distance[otherType];
3238 	if (op->co_opcode == CIFOP_BLOATMAX)
3239 	{
3240 	    if (tmp > bloat) bloat = tmp;
3241 	}
3242 	else if (tmp < bloat) bloat = tmp;
3243     }
3244     if ((bloat < 10000000) && (bloat > -10000000))
3245 	area.r_ytop += bloat;
3246 
3247     /* Now the right side. */
3248 
3249     if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3250     else bloat = 10000000;
3251     for (t = TR(tile); TOP(t) > BOTTOM(tile); t = LB(t))
3252     {
3253 	otherType = TiGetType(t);
3254 	if (otherType == type) continue;
3255 	tmp = bloats->bl_distance[otherType];
3256 	if (op->co_opcode == CIFOP_BLOATMAX)
3257 	{
3258 	    if (tmp > bloat) bloat = tmp;
3259 	}
3260 	else if (tmp < bloat) bloat = tmp;
3261     }
3262     if ((bloat < 10000000) && (bloat > -10000000))
3263 	area.r_xtop += bloat;
3264 
3265     /* Lastly, do the bottom side. */
3266 
3267     if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3268     else bloat = 10000000;
3269     for (t = LB(tile); LEFT(t) < RIGHT(tile); t = TR(t))
3270     {
3271 	otherType = TiGetType(t);
3272 	if (otherType == type) continue;
3273 	tmp = bloats->bl_distance[otherType];
3274 	if (op->co_opcode == CIFOP_BLOATMAX)
3275 	{
3276 	    if (tmp > bloat) bloat = tmp;
3277 	}
3278 	else if (tmp < bloat) bloat = tmp;
3279     }
3280     if ((bloat < 10000000) && (bloat > -10000000))
3281 	area.r_ybot -= bloat;
3282 
3283     /* Make sure the tile didn't shrink into negativity.  If it's
3284      * ok, paint it into the new plane being built.
3285      */
3286 
3287     if ((area.r_xbot > area.r_xtop) || (area.r_ybot > area.r_ytop))
3288     {
3289 	TiToRect(tile, &area);
3290 	area.r_xbot *= cifScale;
3291 	area.r_xtop *= cifScale;
3292 	area.r_ybot *= cifScale;
3293 	area.r_ytop *= cifScale;
3294 	CIFError(&area, "tile inverted by shrink");
3295     }
3296     else
3297 	DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &area,
3298 		CIFPaintTable, (PaintUndoInfo *) NULL);
3299 
3300     CIFTileOps += 1;
3301     return 0;
3302 }
3303 
3304 /*
3305  * ----------------------------------------------------------------------------
3306  *
3307  * inside_triangle --
3308  *
3309  *	Test if the specified rectangle is completely inside the tile.
3310  *	Tile is presumed to be a split tile.
3311  *
3312  * Results:
3313  *	TRUE if inside, FALSE if outside or overlapping.
3314  *
3315  * Side Effects:
3316  *	None.
3317  *
3318  * Notes:
3319  *	This is an optimized version of the code in DBtiles.c.  It
3320  *	assumes that the square is never infinite.
3321  *
3322  * ----------------------------------------------------------------------------
3323  */
3324 
3325 bool
inside_triangle(rect,tile)3326 inside_triangle(rect, tile)
3327     Rect *rect;
3328     Tile *tile;
3329 {
3330     int theight, twidth;
3331     dlong f1, f2, f3, f4;
3332 
3333     theight = TOP(tile) - BOTTOM(tile);
3334     twidth = RIGHT(tile) - LEFT(tile);
3335 
3336     f1 = (dlong)(TOP(tile) - rect->r_ybot) * twidth;
3337     f2 = (dlong)(rect->r_ytop - BOTTOM(tile)) * twidth;
3338 
3339     if (SplitLeftType(tile) != TT_SPACE)
3340     {
3341         /* Inside-of-triangle check */
3342         f4 = (dlong)(rect->r_xbot - LEFT(tile)) * theight;
3343         if (SplitDirection(tile) ? (f1 > f4) : (f2 > f4))
3344 	    return TRUE;
3345     }
3346     else
3347     {
3348         /* Inside-of-triangle check */
3349         f3 = (dlong)(RIGHT(tile) - rect->r_xtop) * theight;
3350         if (SplitDirection(tile) ? (f2 > f3) : (f1 > f3))
3351 	    return TRUE;
3352     }
3353     return FALSE;
3354 }
3355 
3356 /*
3357  * ----------------------------------------------------------------------------
3358  *
3359  * cifContactFunc --
3360  *
3361  *	Called for each relevant tile when chopping up contacts into
3362  *	square cuts using the procedure of using a pre-defined cell
3363  *	definition of a single contact and arraying the cell.
3364  *	Technically, this is not a CIF function because CIF does not
3365  *	have an array method for cells, so there is no advantage to
3366  *	drawing lots of subcells in place of drawing lots of boxes.
3367  *	In GDS, however, the array method is much more compact than
3368  *	drawing individual cuts when the array size is larger than 1.
3369  *
3370  * Results:
3371  *	Normally returns 0 to keep the search going.  Return 1 if
3372  *	the contact type cannot be found, which halts the search.
3373  *
3374  * Side effects:
3375  *	Stuff is painted into cifPlane.
3376  *
3377  * ----------------------------------------------------------------------------
3378  */
3379 
3380 int
cifContactFunc(tile,csi)3381 cifContactFunc(tile, csi)
3382     Tile *tile;			/* Tile to be diced up. */
3383     CIFSquaresInfo *csi; 	/* Describes how to generate squares. */
3384 {
3385     Rect area;
3386     int i, nAcross, j, nUp, left, bottom, pitch, halfsize;
3387     bool result;
3388     SquaresData *squares = csi->csi_squares;
3389 
3390     /* For now, don't allow squares on non-manhattan tiles */
3391     if (IsSplit(tile))
3392 	return 0;
3393 
3394     TiToRect(tile, &area);
3395     pitch = squares->sq_size + squares->sq_sep;
3396 
3397     nAcross = (area.r_xtop - area.r_xbot + squares->sq_sep
3398 	    - (2 * squares->sq_border)) / pitch;
3399     if (nAcross == 0)
3400     {
3401 	left = (area.r_xbot + area.r_xtop - squares->sq_size) / 2;
3402 	if (left >= area.r_xbot) nAcross = 1;
3403     }
3404     else
3405 	left = (area.r_xbot + area.r_xtop + squares->sq_sep
3406 		- (nAcross * pitch)) / 2;
3407 
3408     nUp = (area.r_ytop - area.r_ybot + squares->sq_sep
3409 	    - (2 * squares->sq_border)) / pitch;
3410     if (nUp == 0)
3411     {
3412 	bottom = (area.r_ybot + area.r_ytop - squares->sq_size) / 2;
3413 	if (bottom >= area.r_ybot) nUp = 1;
3414     }
3415     else
3416 	bottom = (area.r_ybot + area.r_ytop + squares->sq_sep
3417 		- (nUp * pitch)) / 2;
3418 
3419     /* Lower-left coordinate should be centered on the contact cut, as
3420      * contact definitions are centered on the origin.
3421      */
3422     halfsize = (squares->sq_size / 2);
3423     left += halfsize;
3424     bottom += halfsize;
3425 
3426     result = CalmaGenerateArray((FILE *)csi->csi_client, csi->csi_type,
3427 		left, bottom, pitch, nAcross, nUp);
3428 
3429     return (result == TRUE) ? 0 : 1;
3430 }
3431 
3432 /*
3433  * ----------------------------------------------------------------------------
3434  *
3435  * cifSlotFunc --
3436  *
3437  * 	Called for each relevant tile area when chopping areas up into
3438  *	slots (rectangles).  Determines how to divide up the area into
3439  *	slots, and generates the number of rows, columns, and the lower-
3440  *	left-most cut rectangle.
3441  *
3442  * Results:
3443  *	Always return 0
3444  *
3445  * Side effects:
3446  *	Pointers "rows", "columns", and "cut" are filled with
3447  *	appropriate values.
3448  *
3449  * ----------------------------------------------------------------------------
3450  */
3451 
3452 int
cifSlotFunc(area,op,numY,numX,cut,vertical)3453 cifSlotFunc(area, op, numY, numX, cut, vertical)
3454     Rect  *area;		/* Area to be diced up			*/
3455     CIFOp *op;			/* Describes how to generate squares.	*/
3456     int *numY, *numX;		/* Return values: # rows and # columns 	*/
3457     Rect *cut;			/* initial (lower left) cut area 	*/
3458     bool vertical;		/* if TRUE, slot is aligned vertically	*/
3459 {
3460     int i, j, xpitch, ypitch, delta, limit;
3461     int *axtop, *axbot, *aytop, *aybot;
3462     int *sxtop, *sxbot, *sytop, *sybot;
3463     int *rows, *columns;
3464     SlotsData *slots = (SlotsData *)op->co_client;
3465 
3466     /* Orient to the short/long orientation of the tile */
3467 
3468     /* Assume a vertical tile;  if not, reorient area and remember */
3469     if (vertical)
3470     {
3471 	axbot = &area->r_xbot;
3472 	aybot = &area->r_ybot;
3473 	axtop = &area->r_xtop;
3474 	aytop = &area->r_ytop;
3475 	sxbot = &cut->r_xbot;
3476 	sybot = &cut->r_ybot;
3477 	sxtop = &cut->r_xtop;
3478 	sytop = &cut->r_ytop;
3479 	rows = numY;
3480 	columns = numX;
3481     }
3482     else
3483     {
3484 	axbot = &area->r_ybot;
3485 	aybot = &area->r_xbot;
3486 	axtop = &area->r_ytop;
3487 	aytop = &area->r_xtop;
3488 	sxbot = &cut->r_ybot;
3489 	sybot = &cut->r_xbot;
3490 	sxtop = &cut->r_ytop;
3491 	sytop = &cut->r_xtop;
3492 	rows = numX;
3493 	columns = numY;
3494     }
3495 
3496     xpitch = slots->sl_ssize + slots->sl_ssep;
3497 
3498 calcX:
3499     *columns = (*axtop - *axbot + slots->sl_ssep - (2 * slots->sl_sborder)) / xpitch;
3500     if (*columns == 0)
3501     {
3502 	*rows = 0;
3503 	return 0;
3504 	// *sxbot = (*axbot + *axtop - slots->sl_ssize) / 2;
3505 	// if (*sxbot >= *axbot) *columns = 1;
3506     }
3507     else
3508 	*sxbot = (*axbot + *axtop + slots->sl_ssep - (*columns * xpitch)) / 2;
3509     *sxtop = *sxbot + slots->sl_ssize;
3510 
3511     /* Check that we are not violating any gridlimit */
3512 
3513     limit = CIFCurStyle->cs_gridLimit;
3514 
3515     if (CIFCurStyle && (limit > 1))
3516     {
3517 	delta = abs(*sxbot) % limit;
3518 	if (delta > 0)
3519 	{
3520 	    if (*sxbot >= 0)
3521 		*axtop -= 2 * delta;
3522 	    else
3523 		*axtop += 2 * delta;
3524 	    goto calcX;
3525 	}
3526     }
3527 
3528     if (slots->sl_lsize > 0)
3529     {
3530 	ypitch = slots->sl_lsize + slots->sl_lsep;
3531 calcY:
3532 	*rows = (*aytop - *aybot + slots->sl_lsep - (2 * slots->sl_lborder)) / ypitch;
3533 	if (*rows == 0)
3534 	{
3535 	    return 0;
3536 	    // *sybot = (*aybot + *aytop - slots->sl_lsize) / 2;
3537 	    // if (*sybot >= *aybot) *rows = 1;
3538 	}
3539 	else
3540 	    *sybot = (*aybot + *aytop + slots->sl_lsep - (*rows * ypitch)) / 2;
3541 	*sytop = *sybot + slots->sl_lsize;
3542 
3543 	/* Check that we are not violating any gridlimit */
3544 
3545 	if (CIFCurStyle && (limit > 1))
3546 	{
3547 	    delta = abs(*sybot) % limit;
3548 	    if (delta > 0)
3549 	    {
3550 		if (*sybot >= 0)
3551 		    *aytop -= 2 * delta;
3552 		else
3553 		    *aytop += 2 * delta;
3554 		goto calcY;
3555 	    }
3556 	}
3557     }
3558     else
3559     {
3560 	*rows = 1;
3561 	*sybot = *aybot + slots->sl_lborder;
3562 	*sytop = *aytop - slots->sl_lborder;
3563 	/* There's no space to fit a slot */
3564 	if (*sytop - *sybot <= 0)
3565 	    return 0;
3566     }
3567 
3568     /* To be done---slot offsets */
3569 
3570     return 0;
3571 }
3572 
3573 /*
3574  * ----------------------------------------------------------------------------
3575  *
3576  * cifSquareFunc --
3577  *
3578  * 	Called for each relevant rectangle when chopping areas up into
3579  *	squares.   Determines the number of rows and columns in the area
3580  *	and returns these and the area of the lower-left cut.
3581  *
3582  * Results:
3583  *	Always return 0
3584  *
3585  * Side effects:
3586  *	Results filled in the pointer positions passed to the function
3587  *
3588  * ----------------------------------------------------------------------------
3589  */
3590 
3591 int
cifSquareFunc(area,op,rows,columns,cut)3592 cifSquareFunc(area, op, rows, columns, cut)
3593     Rect *area;			/* Area to be diced up */
3594     CIFOp *op;			/* Describes how to generate squares.	*/
3595     int *rows, *columns;	/* Return values: # rows and # columns,	*/
3596     Rect *cut;			/* initial (lower left) cut area.	*/
3597 {
3598     int pitch, delta, limit;
3599     bool glimit;
3600     SquaresData *squares = (SquaresData *)op->co_client;
3601 
3602     limit = CIFCurStyle->cs_gridLimit;
3603 
3604     glimit = (CIFCurStyle && (limit > 1)) ? TRUE : FALSE;
3605     pitch = squares->sq_size + squares->sq_sep;
3606 
3607     /* Compute the real border to leave around the sides.  If only
3608      * one square will fit in a particular direction, center it
3609      * regardless of the requested border size.  If more than one
3610      * square will fit, then fit it in extras only if at least the
3611      * requested border size can be left.  Also center things in the
3612      * rectangle, so that the box's exact size doesn't matter. This
3613      * trickiness is done so that coincident contacts from overlapping
3614      * cells always have their squares line up, regardless of the
3615      * orientation of the cells.
3616      *
3617      * Update 1/13/09:  Removed the "feature" that allows contact
3618      * cuts that violate the border requirement.  The "slots" rule
3619      * can be used if necessary to generate cuts with different
3620      * border allowances.
3621      */
3622 
3623 sqX:
3624     *columns = (area->r_xtop - area->r_xbot + squares->sq_sep
3625 	    - (2 * squares->sq_border)) / pitch;
3626     if (*columns == 0)
3627     {
3628 	*rows = 0;
3629 	return 0;
3630 
3631 	// cut->r_xbot = (area->r_xbot + area->r_xtop - squares->sq_size) / 2;
3632 	// if (cut->r_xbot >= area->r_xbot) *columns = 1;
3633     }
3634     else
3635     {
3636 	cut->r_xbot = (area->r_xbot + area->r_xtop + squares->sq_sep
3637 		- (*columns * pitch)) / 2;
3638     }
3639 
3640     /* Check for any gridlimit violation */
3641 
3642     if (glimit)
3643     {
3644 	delta = abs(cut->r_xbot) % limit;
3645 	if (delta > 0)
3646 	{
3647 	    area->r_xtop -= 2 * delta;
3648 	    goto sqX;
3649 	}
3650     }
3651 
3652 sqY:
3653     *rows = (area->r_ytop - area->r_ybot + squares->sq_sep
3654 	    - (2 * squares->sq_border)) / pitch;
3655     if (*rows == 0)
3656     {
3657 	return 0;
3658 
3659 	// cut->r_ybot = (area->r_ybot + area->r_ytop - squares->sq_size) / 2;
3660 	// if (cut->r_ybot >= area->r_ybot) *rows = 1;
3661     }
3662     else
3663     {
3664 	cut->r_ybot = (area->r_ybot + area->r_ytop + squares->sq_sep
3665 		- (*rows * pitch)) / 2;
3666     }
3667 
3668     /* Check for any gridlimit violation */
3669 
3670     if (glimit)
3671     {
3672 	delta = abs(cut->r_ybot) % limit;
3673 	if (delta > 0)
3674 	{
3675 	    area->r_ytop -= 2 * delta;
3676 	    goto sqY;
3677 	}
3678     }
3679 
3680     cut->r_xtop = cut->r_xbot + squares->sq_size;
3681     cut->r_ytop = cut->r_ybot + squares->sq_size;
3682     return 0;
3683 }
3684 
3685 /*
3686  * ----------------------------------------------------------------------------
3687  *
3688  * cifSquareGridFunc --
3689  *
3690  * 	Called for each relevant rectangle when chopping areas up into
3691  *	squares.   Determines the number of rows and columns in the area
3692  *	and returns these and the area of the lower-left cut.
3693  *
3694  * Results:
3695  *	Always return 0
3696  *
3697  * Side effects:
3698  *	Results filled in the pointer positions passed to the function
3699  *
3700  * ----------------------------------------------------------------------------
3701  */
3702 
3703 int
cifSquareGridFunc(area,op,rows,columns,cut)3704 cifSquareGridFunc(area, op, rows, columns, cut)
3705     Rect *area;			/* Area to be diced up */
3706     CIFOp *op;			/* Describes how to generate squares.	*/
3707     int *rows, *columns;	/* Return values: # rows and # columns,	*/
3708     Rect *cut;			/* initial (lower left) cut area.	*/
3709 {
3710     Rect locarea;
3711     int left, bottom, right, top, pitch;
3712     int gridx, gridy, margin;
3713     SquaresData *squares = (SquaresData *)op->co_client;
3714 
3715     /*
3716      * It may be necessary to generate contacts on a specific grid; e.g.,
3717      * to avoid placing contacts at half-lambda.  If this is the case,
3718      * then the DRC section of the techfile should specify "no overlap"
3719      * for these types.
3720      *
3721      * This routine has been simplified.  It flags a warning when there
3722      * is not enough space for a contact cut, rather than attempting to
3723      * draw a cut without enough border area.  The routine has also been
3724      * extended to allow different x and y grids to be specified.  This
3725      * allows certain tricks, such as generating offset contact grids on
3726      * a pad, as required by some processes.
3727      */
3728 
3729     pitch = squares->sq_size + squares->sq_sep;
3730     gridx = squares->sq_gridx;
3731     gridy = squares->sq_gridy;
3732 
3733     locarea.r_xtop = area->r_xtop - squares->sq_border;
3734     locarea.r_ytop = area->r_ytop - squares->sq_border;
3735     locarea.r_xbot = area->r_xbot + squares->sq_border;
3736     locarea.r_ybot = area->r_ybot + squares->sq_border;
3737 
3738     left = locarea.r_xbot / gridx;
3739     left *= gridx;
3740     if (left < locarea.r_xbot) left += gridx;
3741 
3742     bottom = locarea.r_ybot / gridy;
3743     bottom *= gridy;
3744     if (bottom < locarea.r_ybot) bottom += gridy;
3745 
3746     *columns = (locarea.r_xtop - left + squares->sq_sep) / pitch;
3747     if (*columns == 0)
3748     {
3749 	*rows = 0;
3750 	return 0;
3751     }
3752 
3753     *rows = (locarea.r_ytop - bottom + squares->sq_sep) / pitch;
3754     if (*rows == 0) return 0;
3755 
3756     /* Center the contacts while remaining on-grid */
3757     right = left + *columns * squares->sq_size + (*columns - 1) * squares->sq_sep;
3758     top = bottom + *rows * squares->sq_size + (*rows - 1) * squares->sq_sep;
3759     margin = ((locarea.r_xtop - right) - (left - locarea.r_xbot)) / (gridx * 2);
3760     locarea.r_xbot = left + margin * gridx;
3761     margin = ((locarea.r_ytop - top) - (bottom - locarea.r_ybot)) / (gridy * 2);
3762     locarea.r_ybot = bottom + margin * gridy;
3763 
3764     cut->r_ybot = locarea.r_ybot;
3765     cut->r_ytop = cut->r_ybot + squares->sq_size;
3766     cut->r_xbot = locarea.r_xbot;
3767     cut->r_xtop = cut->r_xbot + squares->sq_size;
3768     return 0;
3769 }
3770 
3771 
3772 /*
3773  * ----------------------------------------------------------------------------
3774  *
3775  * cifSrTiles --
3776  *
3777  * 	This is a utility procedure that just calls DBSrPaintArea
3778  *	one or more times for the planes being used in processing
3779  *	one CIFOp.
3780  *
3781  * Results:
3782  *	None.
3783  *
3784  * Side effects:
3785  *	This procedure itself has no side effects.  For each of the
3786  *	paint or temporary planes indicated in cifOp, we call
3787  *	DBSrPaintArea to find the desired tiles in the desired
3788  *	area for the operation.  DBSrPaintArea is given func as a
3789  *	search function, and cdArg as ClientData.
3790  *
3791  * ----------------------------------------------------------------------------
3792  */
3793 
3794 void
cifSrTiles(cifOp,area,cellDef,temps,func,cdArg)3795 cifSrTiles(cifOp, area, cellDef, temps, func, cdArg)
3796     CIFOp *cifOp;		/* Geometric operation being processed. */
3797     Rect *area;			/* Area of Magic paint to consider. */
3798     CellDef *cellDef;		/* CellDef to search for paint. */
3799     Plane *temps[];		/* Planes to use for temporaries. */
3800     int (*func)();		/* Search function to pass to DBSrPaintArea. */
3801     ClientData cdArg;		/* Client data for func. */
3802 {
3803     TileTypeBitMask maskBits;
3804     TileType t;
3805     Tile *tp;
3806     int i;
3807     BloatData *bloats;
3808 
3809     /* When reading data from a cell, it must first be scaled to
3810      * CIF units.  Check for CIFCurStyle, as we don't want to
3811      * crash while reading CIF/GDS just becuase the techfile
3812      * "cifoutput" section was blank.
3813      */
3814 
3815     cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
3816 
3817     /* Bloat operations (except bloat-all) have to be in a single plane */
3818 
3819     switch (cifOp->co_opcode) {
3820 	case CIFOP_BLOAT:
3821 	case CIFOP_BLOATMIN:
3822 	case CIFOP_BLOATMAX:
3823 	    bloats = (BloatData *)cifOp->co_client;
3824 	    i = bloats->bl_plane;
3825 	    maskBits = DBPlaneTypes[i];
3826 	    TTMaskAndMask(&maskBits, &cifOp->co_paintMask);
3827 	    if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
3828 		DBSrPaintArea((Tile *) NULL, cellDef->cd_planes[i],
3829 				area, &cifOp->co_paintMask, func, cdArg);
3830 	    break;
3831 
3832 	default:
3833 	    for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
3834 	    {
3835 		maskBits = DBPlaneTypes[i];
3836 		TTMaskAndMask(&maskBits, &cifOp->co_paintMask);
3837 		if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
3838 		    (void) DBSrPaintArea((Tile *) NULL, cellDef->cd_planes[i],
3839 			area, &cifOp->co_paintMask, func, cdArg);
3840 	    }
3841 	    break;
3842     }
3843 
3844     /* When processing CIF data, use everything in the plane. */
3845 
3846     cifScale = 1;
3847     for (t = 0; t < TT_MAXTYPES; t++, temps++)
3848 	if (TTMaskHasType(&cifOp->co_cifMask, t))
3849 	    (void) DBSrPaintArea((Tile *) NULL, *temps, &TiPlaneRect,
3850 		&CIFSolidBits, func, (ClientData) cdArg);
3851 }
3852 
3853 /* Data structure to pass plane and minimum width to the callback function */
3854 typedef struct _bridgeLimStruct {
3855     Plane       *plane;
3856     BridgeData	*bridge;
3857     CellDef     *def;
3858     Plane       **temps;
3859     TileTypeBitMask co_paintMask;/* Zero or more paint layers to consider. */
3860     TileTypeBitMask co_cifMask;  /* Zero or more other CIF layers. */
3861 } BridgeLimStruct;
3862 
3863 static int xOverlap, yOverlap;
3864 
3865 /* Bridge-lim Check data structure */
3866 typedef struct _bridgeLimCheckStruct {
3867    Tile *tile;		/* Tile that triggered search (ignore this tile) */
3868    int	direction;	/* What outside corner to look for */
3869    Tile *violator;	/* Return the violator tile in this space */
3870    TileType checktype;	/* Type to check for, either TT_SPACE or CIF_SOLIDTYPE */
3871    long sqdistance;     /* Square of the minimum distance */
3872 } BridgeLimCheckStruct;
3873 /*
3874  *-----------------------------------------------------------------------
3875  * Callback function for bridgeLimSrTiles used when a limiting layer tile
3876  * was found in the specified area. If calcOverlap is TRUE then the xOverlap
3877  * and yOverlap are updated and return 0 to continue searching. Otherwise
3878  * return 1 to stop the search.
3879  *-----------------------------------------------------------------------
3880  */
3881 int
bridgeLimFound(tile,calcOverlap)3882 bridgeLimFound(tile, calcOverlap)
3883     Tile *tile;
3884     bool calcOverlap;
3885 {
3886     if (calcOverlap)
3887     {
3888         if (RIGHT(tile) > xOverlap)
3889                 xOverlap = RIGHT(tile);
3890         if (TOP(tile) > yOverlap)
3891                 yOverlap = TOP(tile);
3892         return 0;       // continue searching
3893     } else
3894         return 1;       // tile found, stop the search
3895 }
3896 
3897 /*
3898  *------------------------------------------------------------------------
3899  * Callback function used in bridge-lim operations to find if the specified
3900  * area contains tiles of the limiting layers.
3901  *------------------------------------------------------------------------
3902  */
3903 int
bridgeLimSrTiles(brlims,area,calcOverlap)3904 bridgeLimSrTiles(brlims, area, calcOverlap)
3905     BridgeLimStruct *brlims;    /* Bridge-Lim structure. */
3906     Rect *area;                 /* Area of Magic paint to consider. */
3907     bool calcOverlap;           /* TRUE to calculate the overlap of the limiting tiles in the specified area. */
3908 {
3909     TileTypeBitMask maskBits;
3910     TileType t;
3911     int i;
3912     Plane **temps = brlims->temps;
3913     xOverlap = area->r_xbot;
3914     yOverlap = area->r_ybot;
3915 
3916     for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
3917     {
3918 	maskBits = DBPlaneTypes[i];
3919 	TTMaskAndMask(&maskBits, &brlims->co_paintMask);
3920 	if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
3921 	    if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, bridgeLimFound, calcOverlap))
3922 		return 0;
3923     }
3924 
3925     for (t = 0; t < TT_MAXTYPES; t++, temps++)
3926         if (TTMaskHasType(&brlims->co_cifMask, t))
3927            if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, bridgeLimFound, calcOverlap))
3928                 return 0;
3929 
3930     if (( xOverlap != area->r_xbot) || (yOverlap != area->r_ybot))
3931         return 0;       //Constraint tile found
3932     else
3933         return 1;       //Nothing found
3934 }
3935 
3936 /*
3937  * ----------------------------------------------------------------------------
3938  *
3939  * cifBridgeLimFunc0 --
3940  *
3941  * 	Called for each relevant tile during bridge-lim operations.  The
3942  *	bridge-lim operation is similar to the bridge operation with the
3943  *	difference that the material created to meet the minimum spacing/width
3944  *	rules do not overlap the limiting layers.
3945  *
3946  * Results:
3947  *	Always returns 0 to keep the search alive.
3948  *
3949  * Side effects:
3950  *	May paint into cifNewPlane
3951  *
3952  * Algorithm (based on maximum horizontal stripes rule):
3953  * This function grows dimentions of tiles to meet a minimimum width rule (only
3954  * applies to vertical or horizontal directions). This is done in two steps:
3955  * 	1. Adjust tile width to accomplish the minimimum width rule, limited by
3956  *	the constraint layers.
3957  *	2. Search top and bottom tiles of same type, for each segment verify if
3958  *	height meets the minimimum value, if not, adjust the segment height
3959  *	but do not paint over limiting layer tiles.
3960  * ----------------------------------------------------------------------------
3961  */
3962 int
cifBridgeLimFunc0(tile,brlims)3963 cifBridgeLimFunc0(tile, brlims)
3964     Tile *tile;
3965     BridgeLimStruct *brlims;
3966 {
3967     Plane *plane = brlims->plane;
3968     Rect area, parea;
3969     int minDistance = brlims->bridge->br_width;
3970     int width, height, ybot0, tp2lim;
3971     Tile *tp, *tp2;
3972 
3973     TiToRect(tile, &area);
3974 
3975     /* Check whole tile for minimum width */
3976     width = area.r_xtop - area.r_xbot;
3977     if (width < minDistance)
3978     {
3979 	area.r_xbot = area.r_xtop - minDistance;
3980         if (!bridgeLimSrTiles(brlims, &area, TRUE))
3981 	{
3982             area.r_xbot = MIN(LEFT(tile), xOverlap);
3983 	    area.r_xtop = area.r_xbot + minDistance;
3984 	}
3985     }
3986 
3987 	/* If there is another tile on top or bottom, and the height is	*/
3988 	/* less than minimum, then extend height in the direction of	*/
3989 	/* the bordering tile.  Otherwise, if the height is less than	*/
3990 	/* minimum, then grow considering the limiting layers.	*/
3991 
3992 	height = area.r_ytop - area.r_ybot;
3993 	if (height < minDistance)
3994 	{
3995          for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
3996             {
3997             tp2lim = MAX(LEFT(tp), area.r_xbot);
3998             for (tp2 = RT(tile); RIGHT(tp2) > tp2lim; tp2 = BL(tp2))
3999                 if (LEFT(tp2) < RIGHT(tp))
4000                 {
4001                    parea.r_xbot = MAX(LEFT(tp2), tp2lim);
4002                    parea.r_xtop = MIN(MIN(RIGHT(tp2), RIGHT(tp)), area.r_xtop);
4003                    if (TiGetBottomType(tp2) == TiGetTopType(tile))
4004                         parea.r_ytop = TOP(tp2);
4005                    else
4006                         parea.r_ytop = area.r_ytop;
4007                    if (TiGetTopType(tp) == TiGetBottomType(tile))
4008                         ybot0 = BOTTOM(tp);
4009                    else
4010                         ybot0 = area.r_ybot;
4011                    height = parea.r_ytop - ybot0;
4012                    if (height < minDistance)
4013                    {
4014                         parea.r_ybot = parea.r_ytop - minDistance;
4015                         if (!bridgeLimSrTiles(brlims, &parea, TRUE))
4016                         {
4017                            parea.r_ybot = MIN(ybot0 , yOverlap);
4018                            parea.r_ytop = parea.r_ybot + minDistance;
4019                         }
4020                         DBPaintPlane(cifPlane, &parea, CIFPaintTable, (PaintUndoInfo *) NULL);
4021                    }
4022                 }
4023             }
4024         }
4025     DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4026     return 0;
4027 }
4028 
4029 /*
4030  *-----------------------------------------------------------------------
4031  * Callback function for cifBridgeLimFunc1 and cifBridgeLimFunc2 to find if
4032  * there are violator cells in the search area.	 If a violator cell is
4033  * found, then put the tile pointer in the BridgeCheckStruct and return
4034  * value 1 to stop the search.	Otherwise return 0 to keep going.
4035  *-----------------------------------------------------------------------
4036  */
4037 int
bridgeLimCheckFunc(tile,brlimcs)4038 bridgeLimCheckFunc(tile, brlimcs)
4039     Tile *tile;
4040     BridgeLimCheckStruct *brlimcs;
4041 {
4042     int dir = brlimcs->direction;
4043     Tile *self = brlimcs->tile;
4044     Tile *tp1, *tp2;
4045     TileType checktype = brlimcs->checktype;
4046     long sqdistance = brlimcs->sqdistance;
4047     int dx, dy;
4048     long sqcheck;
4049 
4050     if (self == tile) return 0;	    /* Ignore the triggering tile */
4051 
4052     switch (dir) {
4053 	case BRIDGE_NW:
4054 	    /* Ignore tile if split, and SE corner is clipped */
4055 	    if (IsSplit(tile))
4056 	    if (TiGetRightType(tile) == checktype || TiGetBottomType(tile) == checktype)
4057 		break;
4058 	    for (tp1 = RT(tile); LEFT(tp1) > LEFT(tile); tp1 = BL(tp1));
4059 	    for (tp2 = BL(tile); TOP(tp2) < TOP(tile); tp2 = RT(tp2));
4060 	    if ((TiGetBottomType(tp1) == checktype) &&
4061 		    (TiGetRightType(tp2) == checktype))
4062 	    {
4063 		dx = LEFT(tile) - RIGHT(self);
4064 		dy = BOTTOM(self) - TOP(tile);
4065 		if ((dx > 0) && (dy > 0))
4066 		{
4067 		   sqcheck = (long)dx*dx + (long)dy*dy;
4068 		   if (sqcheck >= sqdistance)
4069 			return 0;
4070 		}
4071 		brlimcs->violator = tile;
4072 		return 1;	/* Violator found */
4073 	    }
4074 	    break;
4075 	case BRIDGE_SW:
4076 	    /* Ignore tile if split, and NE corner is clipped */
4077 	    if (IsSplit(tile))
4078 	    if (TiGetRightType(tile) == checktype || TiGetTopType(tile) == checktype)
4079 		break;
4080 	    tp1 = LB(tile);
4081 	    tp2 = BL(tile);
4082 	    if ((TiGetTopType(tp1) == checktype) &&
4083 		    (TiGetRightType(tp2) == checktype))
4084 	    {
4085 		dx = LEFT(tile) - RIGHT(self);
4086 		dy = BOTTOM(tile) - TOP(self);
4087 		if ((dx > 0) && (dy > 0))
4088 		{
4089 		   sqcheck = (long)dx*dx + (long)dy*dy;
4090 		   if (sqcheck >= sqdistance)
4091 			return 0;
4092 		}
4093 		brlimcs->violator = tile;
4094 		return 1;	/* Violator found */
4095 	    }
4096 	    break;
4097     }
4098     return 0;	/* Nothing found here, so keep going */
4099 }
4100 
4101 /*
4102  *-----------------------------------------------------------------------
4103  * Callback function used in bridge-lim operations to do not paint areas
4104  * where new bridge overlaps the limiting layer tiles.
4105  *-----------------------------------------------------------------------
4106  */
4107 int
bridgeErase(brlims,area)4108 bridgeErase(brlims, area)
4109     BridgeLimStruct *brlims;    /* Bridge-lim structure. */
4110     Rect *area;                 /* Area of Magic paint to consider. */
4111 {
4112     TileTypeBitMask maskBits;
4113     TileType t;
4114     int i;
4115     Plane **temps = brlims->temps;
4116 
4117     for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
4118     {
4119 	maskBits = DBPlaneTypes[i];
4120 	TTMaskAndMask(&maskBits, &brlims->co_paintMask);
4121 	if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
4122 	    if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
4123 		return 0;
4124     }
4125 
4126     for (t = 0; t < TT_MAXTYPES; t++, temps++)
4127         if (TTMaskHasType(&brlims->co_cifMask, t))
4128            if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, cifPaintFunc, CIFEraseTable))
4129                 return 0;
4130 
4131         return 1;       //Nothing found
4132 }
4133 
4134 /*
4135  * ----------------------------------------------------------------------------
4136  *
4137  * cifBridgeLimFunc1 --
4138  *
4139  * 	Called for each relevant tile during bridge-lim operations.  The
4140  *	bridge-lim operation is similar to the bridge operation with the
4141  *	difference that the material created to meet the minimum spacing/width
4142  *	rules do not overlap the limiting layers.
4143  *
4144  * Results:
4145  *	Always returns 0 to keep the search alive.
4146  *
4147  * Side effects:
4148  *	May paint into cifNewPlane
4149  * ----------------------------------------------------------------------------
4150  */
4151 int
cifBridgeLimFunc1(tile,brlims)4152 cifBridgeLimFunc1(tile, brlims)
4153     Tile *tile;
4154     BridgeLimStruct *brlims;
4155 {
4156     Plane *plane = brlims->plane;
4157     Rect area;
4158     Tile *tp1, *tp2, *tpx;
4159     int width = brlims->bridge->br_width;
4160     int spacing = growDistance;
4161     BridgeLimCheckStruct brlimcs;
4162     brlimcs.sqdistance = (long) spacing * spacing;
4163 
4164     /* If tile is marked, then it has been handled, so ignore it */
4165     if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
4166 
4167     /* Find each tile outside corner (up to four) */
4168 
4169     /* Check for NE outside corner */
4170     tp1 = TR(tile);  /* Tile on right side at the top of this tile */
4171     tp2 = RT(tile);  /* Tile on top side at the right of this tile */
4172     if ((TiGetLeftType(tp1) == TT_SPACE) &&
4173 	    (TiGetBottomType(tp2) == TT_SPACE))
4174     {
4175 	/* Set search box */
4176 	area.r_xbot = RIGHT(tile);
4177 	area.r_xtop = RIGHT(tile) + spacing;
4178 	area.r_ybot = TOP(tile);
4179 	area.r_ytop = TOP(tile) + spacing;
4180 
4181 	/* Find violator tiles */
4182 	brlimcs.tile = tile;
4183 	brlimcs.direction = BRIDGE_SW;
4184 	brlimcs.checktype = TT_SPACE;
4185 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
4186 		    &CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4187 	{
4188 	    tpx = brlimcs.violator;
4189 	    area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4190 	    area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
4191 	    area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
4192 	    area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
4193 	    if (bridgeLimSrTiles(brlims, &area, FALSE))
4194 	    {
4195 		/* First option of bridge can be implemented (there are not limiting tiles in the area)*/
4196 		area.r_ytop = TOP(tile);
4197 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4198 		area.r_xbot = LEFT(tpx);
4199 		area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
4200 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4201 	    }
4202 	    else
4203 	    {
4204 	    area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
4205 	    area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
4206 	    area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4207 	    area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
4208 	    if (bridgeLimSrTiles(brlims, &area, FALSE))
4209 		{
4210 		/* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
4211 		area.r_ybot = BOTTOM(tpx);
4212 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4213 		area.r_xtop = RIGHT(tile);
4214 	    	area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
4215 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4216 		}
4217 		else
4218 		{
4219 		/* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
4220 	    	area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4221 	    	area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
4222 	    	area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4223 	    	area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
4224 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4225 	    	bridgeErase(brlims, &area);
4226 		}
4227 	    }
4228 	}
4229     }
4230 
4231     /* Check for SE outside corner */
4232     for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
4233     for (tp2 = LB(tile); RIGHT(tp1) < RIGHT(tile); tp2 = TR(tp2));
4234     if ((TiGetLeftType(tp1) == TT_SPACE) &&
4235 	    (TiGetTopType(tp2) == TT_SPACE))
4236     {
4237 	/* Set search box */
4238 	area.r_xbot = RIGHT(tile);
4239 	area.r_xtop = RIGHT(tile) + spacing;
4240 	area.r_ybot = BOTTOM(tile) - spacing;
4241 	area.r_ytop = BOTTOM(tile);
4242 
4243 	/* Find violator tiles */
4244 	brlimcs.tile = tile;
4245 	brlimcs.direction = BRIDGE_NW;
4246 	brlimcs.checktype = TT_SPACE;
4247 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
4248 		    &CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4249 	{
4250 	    tpx = brlimcs.violator;
4251 	    area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
4252 	    area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
4253 	    area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4254 	    area.r_ytop = MAX(TOP(tpx), BOTTOM(tile));
4255 	    if (bridgeLimSrTiles(brlims, &area, FALSE))
4256 	    {
4257 		/* First option of bridge can be implemented (there are not limiting tiles in the area)*/
4258 		area.r_xtop = RIGHT(tile);
4259 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4260 	    	area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
4261 		area.r_ytop = TOP(tpx);
4262 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4263 	    }
4264 	    else
4265 	    {
4266 	    area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4267 	    area.r_ybot = MIN(BOTTOM(tile), TOP(tpx));
4268 	    area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
4269 	    area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
4270 	    if (bridgeLimSrTiles(brlims, &area, FALSE))
4271 		{
4272 		/* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
4273 		area.r_xbot = LEFT(tpx);
4274 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4275 	    	area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
4276 		area.r_ybot = BOTTOM(tile);
4277 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4278 		}
4279 		else
4280 		{
4281 		/* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
4282 		area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4283 		area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
4284 		area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4285 		area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
4286 		DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4287 	    	bridgeErase(brlims, &area);
4288 		}
4289 	    }
4290 	}
4291     }
4292 
4293     return 0;
4294 }
4295 
4296 /*
4297  * ----------------------------------------------------------------------------
4298  * cifBridgeLimFunc2 --
4299  *
4300  * 	Called for each relevant tile during bridge-lim operations.  The
4301  *	bridge-lim operation is similar to the bridge operation with the
4302  *	difference that the material created to meet the minimum spacing/width
4303  *	rules do not overlap the limiting layers.
4304  *
4305  * Results:
4306  *	Always returns 0 to keep the search alive.
4307  *
4308  * Side effects:
4309  *	May paint into cifNewPlane
4310  * ----------------------------------------------------------------------------
4311  */
4312 int
cifBridgeLimFunc2(tile,brlims)4313 cifBridgeLimFunc2(tile, brlims)
4314     Tile *tile;
4315     BridgeLimStruct *brlims;
4316 {
4317     Plane *plane = brlims->plane;
4318     Rect area;
4319     Tile *tp1, *tp2, *tpx;
4320     int width = brlims->bridge->br_width;
4321     int thirdOption;
4322     int spacing = growDistance;
4323     BridgeLimCheckStruct brlimcs;
4324     brlimcs.sqdistance = (long) width * width;
4325 
4326     /* If tile is marked, then it has been handled, so ignore it */
4327     if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
4328 
4329     /* Find each tile outside corner (up to four) */
4330 
4331     /* Check for NE outside corner */
4332     tp1 = TR(tile);  /* Tile on right side at the top of this tile */
4333     tp2 = RT(tile);  /* Tile on top side at the right of this tile */
4334     if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
4335 	    (TiGetBottomType(tp2) == CIF_SOLIDTYPE))
4336     {
4337 	/* Set search box */
4338 	area.r_xbot = RIGHT(tile);
4339 	area.r_xtop = RIGHT(tile) + width;
4340 	area.r_ybot = TOP(tile);
4341 	area.r_ytop = TOP(tile) + width;
4342 
4343 	/* Find violator tiles */
4344 	brlimcs.tile = tile;
4345 	brlimcs.direction = BRIDGE_SW;
4346 	brlimcs.checktype = CIF_SOLIDTYPE;
4347 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
4348 		    &DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4349 	{
4350 	    tpx = brlimcs.violator;
4351 	    area.r_xtop = RIGHT(tile);
4352 	    area.r_ytop = TOP(tile);
4353 	    area.r_xbot = LEFT(tpx) - width;
4354 	    area.r_ybot = BOTTOM(tpx) - width;
4355 
4356 	    thirdOption = 0;
4357 	    if (!bridgeLimSrTiles(brlims, &area, FALSE))
4358 	    {
4359 	    	area.r_xtop = RIGHT(tile) + width;
4360 	    	area.r_ytop = TOP(tile) + width;
4361 	    	area.r_xbot = LEFT(tpx);
4362 	    	area.r_ybot = BOTTOM(tpx);
4363 	        if (!bridgeLimSrTiles(brlims, &area, FALSE))
4364 		{
4365 	    	   area.r_xbot = LEFT(tpx) - width;
4366 		   area.r_ybot = BOTTOM(tpx) - width;
4367 	    	   thirdOption = 1;
4368 		}
4369 	    }
4370 	    DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4371 	    if (thirdOption)
4372 	    	bridgeErase(brlims, &area);
4373 	}
4374     }
4375 
4376     /* Check for SE outside corner */
4377     for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
4378     for (tp2 = LB(tile); RIGHT(tp2) < RIGHT(tile); tp2 = TR(tp2));
4379     if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
4380 	    (TiGetTopType(tp2) == CIF_SOLIDTYPE))
4381     {
4382 	/* Set search box */
4383 	area.r_xbot = RIGHT(tile);
4384 	area.r_xtop = RIGHT(tile) + width;
4385 	area.r_ybot = BOTTOM(tile) - width;
4386 	area.r_ytop = BOTTOM(tile);
4387 
4388 	/* Find violator tiles */
4389 	brlimcs.tile = tile;
4390 	brlimcs.direction = BRIDGE_NW;
4391 	brlimcs.checktype = CIF_SOLIDTYPE;
4392 	if (DBSrPaintArea((Tile *) NULL, plane, &area,
4393 		    &DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4394 	{
4395 	    tpx = brlimcs.violator;
4396 	    area.r_xtop = RIGHT(tile) + width;
4397 	    area.r_ytop = TOP(tpx);
4398 	    area.r_xbot = LEFT(tpx);
4399 	    area.r_ybot = BOTTOM(tile) - width;
4400 
4401 	    thirdOption = 0;
4402 	    if (!bridgeLimSrTiles(brlims, &area, FALSE))
4403 	    {
4404 	    	area.r_xtop = RIGHT(tile);
4405 	    	area.r_ytop = TOP(tpx) + width;
4406 	    	area.r_xbot = LEFT(tpx) - width;
4407 	    	area.r_ybot = BOTTOM(tile);
4408 	        if (!bridgeLimSrTiles(brlims, &area, FALSE))
4409 		{
4410 	    	   area.r_xtop = RIGHT(tile) + width;
4411 		   area.r_ybot = BOTTOM(tile) - width;
4412 	    	   thirdOption = 1;
4413 		}
4414 	    }
4415 	    DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4416 	    if (thirdOption)
4417 	    	bridgeErase(brlims, &area);
4418 	}
4419     }
4420 
4421     return 0;
4422 }
4423 
4424 /*
4425  * ----------------------------------------------------------------------------
4426  *
4427  * CIFGenLayer --
4428  *
4429  *	This routine will generate one CIF layer.
4430  *	It provides the core of the CIF generator.
4431  *
4432  * Results:
4433  *	Returns a malloc'ed plane with tiles of type CIF_SOLIDTYPE
4434  *	marking the area of this CIF layer as built up by op.
4435  *
4436  * Side effects:
4437  *	None, except to create a new plane holding the CIF for the layer.
4438  *	The CIF that's generated may fall outside of area... it's what
4439  *	results from considering everything in area.  In most cases the
4440  *	caller will clip the results down to the desired area.
4441  *
4442  * ----------------------------------------------------------------------------
4443  */
4444 
4445 Plane *
CIFGenLayer(op,area,cellDef,origDef,temps,hier,clientdata)4446 CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
4447     CIFOp *op;			/* List of CIFOps telling how to make layer. */
4448     Rect *area;			/* Area to consider when generating CIF.  Only
4449 				 * material in this area will be considered, so
4450 				 * the caller should usually expand his desired
4451 				 * area by one CIF radius.
4452 				 */
4453     CellDef *cellDef;		/* CellDef to search when paint layers are
4454 				 * needed for operation.
4455 				 */
4456     CellDef *origDef;		/* Original CellDef for which output is being
4457 				 * generated (cellDef may be derived from this).
4458 				 */
4459     Plane *temps[];		/* Temporary layers to be used when needed
4460 				 * for operation.
4461 				 */
4462     bool hier;			/* TRUE if called from CIFGenSubcells or CIFGenArrays */
4463     ClientData clientdata;	/*
4464 				 * Data that may be passed to the CIF operation
4465 				 * function.
4466 				 */
4467 {
4468     Plane *temp;
4469     static Plane *nextPlane, *curPlane;
4470     Rect bbox;
4471     CIFOp *tempOp;
4472     CIFSquaresInfo csi;
4473     SearchContext scx;
4474     TileType ttype;
4475     char *netname;
4476     BloatStruct bls;
4477     BridgeStruct brs;
4478     BridgeLimStruct brlims;
4479     BridgeData *bridge;
4480     BloatData *bloats;
4481     bool hstop = FALSE;
4482     char *propvalue;
4483     bool found;
4484 
4485     int (*cifGrowFuncPtr)() = (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN) ?
4486 		cifGrowEuclideanFunc : cifGrowFunc;
4487 
4488     /* Set up temporary planes used during computation.  One of these
4489      * will be returned as the result (whichever is curPlane at the
4490      * end of the computation).  The other is saved for later use.
4491      */
4492 
4493     if (nextPlane == NULL)
4494 	nextPlane = DBNewPlane((ClientData) TT_SPACE);
4495     curPlane = DBNewPlane((ClientData) TT_SPACE);
4496 
4497     /* Go through the geometric operations and process them one
4498      * at a time.
4499      *
4500      * NOTE:  Some opcodes (and whatever follows them) should never
4501      * be run during hierarchical processing.  That includes BOUNDARY,
4502      * SQUARES/SLOTS, BBOX, and NET.
4503      *
4504      * Caveat:  SQUARES/SLOTS followed by GROW can be used to define
4505      * an etch area around a contact;  this should be considered a
4506      * special case that requires hierarchical processing on SQUARES/
4507      * SLOTS.
4508      */
4509 
4510     for ( ; op != NULL; op = op->co_next)
4511     {
4512 	switch (op->co_opcode)
4513 	{
4514 	    /* For AND, first collect all the stuff to be anded with
4515 	     * plane in a temporary plane.  Then find all the places
4516 	     * where there isn't any stuff, and erase from the
4517 	     * current plane.
4518 	     */
4519 
4520 	    case CIFOP_AND:
4521 		DBClearPaintPlane(nextPlane);
4522 		cifPlane = nextPlane;
4523 		cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4524 		    (ClientData) CIFPaintTable);
4525 		cifPlane = curPlane;
4526 		cifScale = 1;
4527 		(void) DBSrPaintArea((Tile *) NULL, nextPlane, &TiPlaneRect,
4528 		    &DBSpaceBits, cifPaintFunc,
4529 		    (ClientData) CIFEraseTable);
4530 		break;
4531 
4532 	    /* For OR, just use cifPaintFunc to OR the areas of all
4533 	     * relevant tiles into plane.  HOWEVER, if the co_client
4534 	     * record is non-NULL and CalmaContactArrays is TRUE,
4535 	     * then for each contact type, we do the paint function
4536 	     * separately, then call the contact array generation
4537 	     * procedure.
4538 	     */
4539 
4540 	    case CIFOP_OR:
4541 		cifPlane = curPlane;
4542 		cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4543 
4544 		if ((op->co_client != (ClientData)NULL)
4545 				&& (CalmaContactArrays == TRUE))
4546 		{
4547 		    TileTypeBitMask paintMask, errMask, *rMask;
4548 		    TileType i, j;
4549 
4550 		    TTMaskZero(&errMask);
4551 		    TTMaskZero(&paintMask);
4552  		    TTMaskSetMask(&paintMask, &op->co_paintMask);
4553 		    for (i = TT_TECHDEPBASE; i < DBNumUserLayers; i++)
4554 		    {
4555 			if (TTMaskHasType(&paintMask, i))
4556 			{
4557 			    TTMaskSetOnlyType(&op->co_paintMask, i);
4558 			    for (j = DBNumUserLayers; j < DBNumTypes; j++)
4559 			    {
4560 				rMask = DBResidueMask(j);
4561 				if (TTMaskHasType(rMask, i))
4562 				    TTMaskSetType(&op->co_paintMask, j);
4563 			    }
4564 
4565 			    cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4566 			    		(ClientData) CIFPaintTable);
4567 
4568 			    csi.csi_squares = (SquaresData *)op->co_client;
4569 			    csi.csi_type = i;
4570 			    csi.csi_client = clientdata;
4571 
4572 			    if (DBSrPaintArea((Tile *) NULL, curPlane,
4573 					&TiPlaneRect, &CIFSolidBits,
4574 					cifContactFunc,	(ClientData) &csi))
4575 			    {
4576 				/* Failure of DBSrPaintArea() (returns 1)
4577 				 * indicates that a contact cell type
4578 				 * could not be found for magic layer i.
4579 				 * Record the error for subsequent handling.
4580 				 */
4581 				TTMaskSetType(&errMask, i);
4582 			    }
4583 			    DBClearPaintPlane(curPlane);
4584 			}
4585 		    }
4586 		    if (!TTMaskIsZero(&errMask))
4587 		    {
4588 			/*
4589 			 * Handle layers for which a contact cell could
4590 			 * not be found in the default manner.
4591 			 */
4592 			TTMaskZero(&op->co_paintMask);
4593  			TTMaskSetMask(&op->co_paintMask, &errMask);
4594 			cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4595 		    		(ClientData) CIFPaintTable);
4596 		    }
4597 
4598 		    /* Recover the original magic layer mask for the cifop */
4599 
4600 		    TTMaskZero(&op->co_paintMask);
4601  		    TTMaskSetMask(&op->co_paintMask, &paintMask);
4602 		}
4603 		else
4604 		{
4605 		    cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4606 		    	(ClientData) CIFPaintTable);
4607 		}
4608 		break;
4609 
4610 	    /* For ANDNOT, do exactly the same thing as OR, except erase
4611 	     * instead of paint.
4612 	     */
4613 
4614 	    case CIFOP_ANDNOT:
4615 		cifPlane = curPlane;
4616 		cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4617 		    (ClientData) CIFEraseTable);
4618 		break;
4619 
4620 	    /* For GROW, just find all solid tiles in the current plane,
4621 	     * and paint a larger version into a new plane.  The switch
4622 	     * the current and new planes.
4623 	     */
4624 
4625 	    case CIFOP_GROW:
4626 		growDistance = op->co_distance;
4627 		DBClearPaintPlane(nextPlane);
4628 		cifPlane = nextPlane;
4629 		cifScale = 1;
4630 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4631 		    &CIFSolidBits, *cifGrowFuncPtr, (ClientData) CIFPaintTable);
4632 		temp = curPlane;
4633 		curPlane = nextPlane;
4634 		nextPlane = temp;
4635 		break;
4636 
4637 	    /* GROWMIN grows non-uniformly to ensure minimum dimensions */
4638 
4639 	    case CIFOP_GROWMIN:
4640 		growDistance = op->co_distance;
4641 		DBClearPaintPlane(nextPlane);
4642 		cifPlane = nextPlane;
4643 		cifScale = 1;
4644 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4645 		    &CIFSolidBits, cifGrowMinFunc, (ClientData)CIFPaintTable);
4646 		temp = curPlane;
4647 		curPlane = nextPlane;
4648 		nextPlane = temp;
4649 		break;
4650 
4651 	    /* GROW_G grows non-uniformly to the indicated grid. */
4652 
4653 	    case CIFOP_GROW_G:
4654 		growDistance = op->co_distance;
4655 		DBClearPaintPlane(nextPlane);
4656 		cifPlane = nextPlane;
4657 		cifScale = 1;
4658 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4659 		    &CIFSolidBits, cifGrowGridFunc, (ClientData) CIFPaintTable);
4660 		temp = curPlane;
4661 		curPlane = nextPlane;
4662 		nextPlane = temp;
4663 		break;
4664 
4665 	    /* SHRINK is just like grow except work from the space tiles. */
4666 
4667 	    case CIFOP_SHRINK:
4668 		growDistance = op->co_distance;
4669 		DBClearPaintPlane(nextPlane);
4670 		DBPaintPlane(nextPlane, &TiPlaneRect, CIFPaintTable,
4671 		    (PaintUndoInfo *) NULL);
4672 		cifPlane = nextPlane;
4673 		cifScale = 1;
4674 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4675 		    &DBSpaceBits, *cifGrowFuncPtr, (ClientData) CIFEraseTable);
4676 		temp = curPlane;
4677 		curPlane = nextPlane;
4678 		nextPlane = temp;
4679 		break;
4680 
4681 	    case CIFOP_CLOSE:
4682 		growDistance = op->co_distance;
4683 		DBClearPaintPlane(nextPlane);
4684 		cifPlane = nextPlane;
4685 		cifScale = 1;
4686 		/* First copy the existing paint into the target plane */
4687 		DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4688 		    	&CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
4689 		DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4690 		    	&DBSpaceBits, cifCloseFunc, (ClientData)&curPlane);
4691 
4692 		temp = curPlane;
4693 		curPlane = nextPlane;
4694 		nextPlane = temp;
4695 		break;
4696 
4697 	    case CIFOP_BRIDGE:
4698 		growDistance = op->co_distance;
4699 		DBClearPaintPlane(nextPlane);
4700 		cifPlane = nextPlane;
4701 		cifScale = 1;
4702 		/* First copy the existing paint into the target plane */
4703 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4704 		    &CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
4705 
4706 		brs.plane = curPlane;
4707 		brs.bridge = (BridgeData *)op->co_client;
4708 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4709 		    &CIFSolidBits, cifBridgeFunc1, (ClientData)&brs);
4710 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4711 		    &DBSpaceBits, cifBridgeFunc2, (ClientData)&brs);
4712 		temp = curPlane;
4713 		curPlane = nextPlane;
4714 		nextPlane = temp;
4715 		break;
4716 
4717 	    case CIFOP_BRIDGELIM:
4718 		growDistance = op->co_distance;
4719 		DBClearPaintPlane(nextPlane);
4720 		cifPlane = nextPlane;
4721 		cifScale = 1;
4722 
4723                 brlims.bridge = (BridgeData *)op->co_client;
4724                 brlims.def = cellDef;
4725                 brlims.temps = temps;
4726 		brlims.co_paintMask = op->co_paintMask;
4727 		brlims.co_cifMask = op->co_cifMask;
4728 
4729 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4730 		    &CIFSolidBits, cifBridgeLimFunc0, (ClientData)&brlims);
4731 		temp = curPlane;
4732                 curPlane = nextPlane;
4733 		brlims.plane = curPlane;
4734 
4735 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4736 		    &CIFSolidBits, cifBridgeLimFunc1, (ClientData)&brlims);
4737 		(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4738 		    &DBSpaceBits, cifBridgeLimFunc2, (ClientData)&brlims);
4739 		curPlane = nextPlane;
4740 		nextPlane = temp;
4741 		break;
4742 
4743 	    case CIFOP_BLOAT:
4744 		cifPlane = curPlane;
4745 		cifSrTiles(op, area, cellDef, temps,
4746 		    cifBloatFunc, op->co_client);
4747 		break;
4748 
4749 	    case CIFOP_BLOATMAX:
4750 	    case CIFOP_BLOATMIN:
4751 		cifPlane = curPlane;
4752 		cifSrTiles(op, area, cellDef, temps,
4753 		    cifBloatMaxFunc, (ClientData) op);
4754 		break;
4755 
4756 	    case CIFOP_BLOATALL:
4757 		cifPlane = curPlane;
4758 		bls.op = op;
4759 		bls.def = cellDef;
4760 		bls.temps = temps;
4761 
4762 	        /* Create a mask of all connecting types (these must be in a single
4763 	         * plane), then call a search function to find all connecting material
4764 	         * of these types (if the bloat types are temp layers, then this mask
4765 	         * is not used).
4766 	         */
4767 
4768 	        bloats = (BloatData *)op->co_client;
4769 	        if (bloats->bl_plane < 0)
4770 	        {
4771 		   /* bl_plane == -1 indicates bloating into a CIF templayer,	*/
4772 		   /* so the only connecting type should be CIF_SOLIDTYPE.	*/
4773 		   TTMaskSetOnlyType(&bls.connect, CIF_SOLIDTYPE);
4774 	        }
4775 	        else
4776 	        {
4777 		    int i;
4778 		    TTMaskZero(&bls.connect);
4779 		    for (i = 0; i < TT_MAXTYPES; i++)
4780 			if (bloats->bl_distance[i] != 0)
4781 			  TTMaskSetType(&bls.connect, i);
4782 	        }
4783 
4784 		cifSrTiles(op, area, cellDef, temps, cifBloatAllFunc, (ClientData)&bls);
4785 
4786 	        /* Reset marked tiles */
4787 
4788 	        if (bloats->bl_plane < 0)   /* Bloat types are CIF types */
4789 	        {
4790 		    bls.temps = temps;
4791 		    for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
4792 			if (bloats->bl_distance[ttype] > 0)
4793 			    (void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
4794 				    &CIFSolidBits, cifProcessResetFunc,
4795 				    (ClientData)NULL);
4796 	        }
4797 	        else
4798 		    DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
4799 			    &TiPlaneRect, &bls.connect, cifProcessResetFunc,
4800 			    (ClientData)NULL);
4801 
4802 		break;
4803 
4804 	    case CIFOP_SQUARES:
4805 		if (hier)
4806 		{
4807 		    if ((op->co_next == NULL) || (op->co_next->co_opcode != CIFOP_GROW))
4808 		    {
4809 		    	hstop = TRUE;	/* Stop hierarchical processing */
4810 		    	break;
4811 		    }
4812 		}
4813 		if (CalmaContactArrays == FALSE)
4814 		{
4815 		    DBClearPaintPlane(nextPlane);
4816 		    cifPlane = nextPlane;
4817 		    cifSquaresFillArea(op, cellDef, curPlane);
4818 		    temp = curPlane;
4819 		    curPlane = nextPlane;
4820 		    nextPlane = temp;
4821 		}
4822 		break;
4823 
4824 	    case CIFOP_SQUARES_G:
4825 		if (hier)
4826 		{
4827 		    if ((op->co_next == NULL) || (op->co_next->co_opcode != CIFOP_GROW))
4828 		    {
4829 		    	hstop = TRUE;	/* Stop hierarchical processing */
4830 		    	break;
4831 		    }
4832 		}
4833 		DBClearPaintPlane(nextPlane);
4834 		cifPlane = nextPlane;
4835 		cifSquaresFillArea(op, cellDef, curPlane);
4836 		temp = curPlane;
4837 		curPlane = nextPlane;
4838 		nextPlane = temp;
4839 		break;
4840 
4841 	    case CIFOP_SLOTS:
4842 		if (hier)
4843 		{
4844 		    if ((op->co_next == NULL) || (op->co_next->co_opcode != CIFOP_GROW))
4845 		    {
4846 		    	hstop = TRUE;	/* Stop hierarchical processing */
4847 		    	break;
4848 		    }
4849 		}
4850 		DBClearPaintPlane(nextPlane);
4851 		cifPlane = nextPlane;
4852 		cifSlotsFillArea(op, cellDef, curPlane);
4853 		temp = curPlane;
4854 		curPlane = nextPlane;
4855 		nextPlane = temp;
4856 		break;
4857 
4858 	    case CIFOP_MAXRECT:
4859 		cifPlane = curPlane;
4860 
4861 		DBClearPaintPlane(nextPlane);
4862 		cifPlane = nextPlane;
4863 		cifRectBoundingBox(op, cellDef, curPlane);
4864 		temp = curPlane;
4865 		curPlane = nextPlane;
4866 		nextPlane = temp;
4867 		break;
4868 
4869 	    case CIFOP_NET:
4870 		if (hier)
4871 		{
4872 		    hstop = TRUE;	/* Stop hierarchical processing */
4873 		    break;
4874 		}
4875 		netname = (char *)op->co_client;
4876 		cifPlane = curPlane;
4877 		ttype = CmdFindNetProc(netname, CIFDummyUse, &bbox, FALSE);
4878 		if (ttype != TT_SPACE)
4879 		{
4880 		    UndoDisable();
4881 		    DBCellClearDef(Select2Def);
4882 		    scx.scx_area = bbox;
4883 		    scx.scx_use = CIFDummyUse;
4884 		    scx.scx_trans = GeoIdentityTransform;
4885 		    DBTreeCopyConnect(&scx, &DBConnectTbl[ttype], 0,
4886 				DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, Select2Use);
4887 		    cifSrTiles(op, area, Select2Def, temps, cifPaintFunc,
4888 				(ClientData) CIFPaintTable);
4889 		    DBCellClearDef(Select2Def);
4890 		    UndoEnable();
4891 		}
4892 		break;
4893 
4894 	    case CIFOP_BOUNDARY:
4895 		if (hier)
4896 		{
4897 		    hstop = TRUE;	/* Stop hierarchical processing */
4898 		    break;
4899 		}
4900 		cifPlane = curPlane;
4901 		/* This function for cifoutput only.  cifinput handled separately. */
4902 
4903 		if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
4904 		{
4905 		    propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
4906 		    if (!found) break;
4907 		    if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
4908 				&bbox.r_xtop, &bbox.r_ytop) != 4) break;
4909 
4910 		    cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4911 		    bbox.r_xbot *= cifScale;
4912 		    bbox.r_xtop *= cifScale;
4913 		    bbox.r_ybot *= cifScale;
4914 		    bbox.r_ytop *= cifScale;
4915 		    cifScale = 1;
4916 		    DBNMPaintPlane(cifPlane, CIF_SOLIDTYPE, &bbox,
4917 				CIFPaintTable, (PaintUndoInfo *)NULL);
4918 		}
4919 		break;
4920 
4921 	    case CIFOP_BBOX:
4922 		if (hier)
4923 		{
4924 		    hstop = TRUE;	/* Stop hierarchical processing */
4925 		    break;
4926 		}
4927 		if (CIFErrorDef == NULL) break;
4928 
4929 		/* co_client contains the flag (1) for top-level only */
4930 		if ((int)op->co_client == 1)
4931 		{
4932 		    /* Only generate output for the top-level cell */
4933 		    int found = 0;
4934 		    CellUse *celluse;
4935 		    for (celluse = CIFErrorDef->cd_parents;
4936 				celluse != (CellUse *) NULL;
4937 				celluse = celluse->cu_nextuse)
4938 		    {
4939 			if (celluse->cu_parent != (CellDef *) NULL)
4940 			    if ((celluse->cu_parent->cd_flags & CDINTERNAL)
4941 					!= CDINTERNAL)
4942 			    {
4943 			 	found = 1;
4944 				break;
4945 			    }
4946 		    }
4947 		    if (found != 0) break;
4948 		}
4949 		cifPlane = curPlane;
4950 		bbox = CIFErrorDef->cd_bbox;
4951 		cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4952 		bbox.r_xbot *= cifScale;
4953 		bbox.r_xtop *= cifScale;
4954 		bbox.r_ybot *= cifScale;
4955 		bbox.r_ytop *= cifScale;
4956 		cifScale = 1;
4957 		DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
4958 			CIFPaintTable, (PaintUndoInfo *)NULL);
4959 		break;
4960 
4961 	    /* The CIFOP_MASKHINTS operator checks the current cell for	*/
4962 	    /* a property with "MASKHINTS_" followed by the name saved	*/
4963 	    /* in the co_client record.  If there is such a property,	*/
4964 	    /* then the property value is parsed for geometry in	*/
4965 	    /* internal units, grouped in sets of four values llx lly	*/
4966 	    /* urx ury.							*/
4967 
4968 	    case CIFOP_MASKHINTS:
4969 		{
4970 		    int j, numfound;
4971 		    char propname[512];
4972 		    char *propptr;
4973 		    char *layername = (char *)op->co_client;
4974 
4975 		    sprintf(propname, "MASKHINTS_%s", layername);
4976 
4977 		    propvalue = (char *)DBPropGet(cellDef, propname, &found);
4978 		    if (!found) break;	    /* No mask hints available */
4979 		    propptr = propvalue;
4980 		    while (*propptr)
4981 		    {
4982 			numfound = sscanf(propptr, "%d %d %d %d",
4983 				&bbox.r_xbot, &bbox.r_ybot,
4984 				&bbox.r_xtop, &bbox.r_ytop);
4985 
4986 			if (numfound != 4)
4987 			{
4988 			    /* To do:  Allow keyword "rect", "tri", or "poly"
4989 			     * at the start of the list and parse accordingly.
4990 			     * For now, this only flags an error.
4991 			     */
4992 			    TxError("%s:  Cannot read rectangle values.\n", propname);
4993 			    break;
4994 			}
4995 			cifPlane = curPlane;
4996 			cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4997 			bbox.r_xbot *= cifScale;
4998 			bbox.r_xtop *= cifScale;
4999 			bbox.r_ybot *= cifScale;
5000 			bbox.r_ytop *= cifScale;
5001 			cifScale = 1;
5002 			DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
5003 				CIFPaintTable, (PaintUndoInfo *)NULL);
5004 			for (j = 0; j < 4; j++)
5005 			{
5006 			    while (*propptr && isspace(*propptr)) propptr++;
5007 			    while (*propptr && !isspace(*propptr)) propptr++;
5008 			}
5009 		    }
5010 		}
5011 		break;
5012 
5013 	    default:
5014 		continue;
5015 	}
5016 	if (hstop) break;	/* Don't process any further rules */
5017     }
5018 
5019     return curPlane;
5020 }
5021 
5022 /*
5023  * ----------------------------------------------------------------------------
5024  *
5025  * CIFGen --
5026  *
5027  * 	This procedure generates a complete set of CIF layers for
5028  *	a particular area of a particular cell.  NOTE: if the argument
5029  *	genAllPlanes is FALSE, only planes for those layers having
5030  *	a bit set in 'layers' are generated; the others are set
5031  *	to NULL.
5032  *
5033  * Results:
5034  *	None.
5035  *
5036  * Side effects:
5037  *	The parameters realPlanes and tempPlanes are modified
5038  *	to hold the CIF and temporary layers for area of cellDef,
5039  *	as determined by the current CIF generation rules.
5040  *
5041  * ----------------------------------------------------------------------------
5042  */
5043 
5044 void
CIFGen(cellDef,origDef,area,planes,layers,replace,genAllPlanes,hier,clientdata)5045 CIFGen(cellDef, origDef, area, planes, layers, replace, genAllPlanes, hier, clientdata)
5046     CellDef *cellDef;		/* Cell for which CIF is to be generated. */
5047     CellDef *origDef;		/* Original cell, if different from cellDef */
5048     Rect *area;			/* Any CIF overlapping this area (in coords
5049 				 * of cellDef) will be generated.  The CIF
5050 				 * will be clipped to this area.
5051 				 */
5052     Plane **planes;		/* Pointer to array of pointers to planes
5053 				 * to hold "real" CIF layers that are
5054 				 * generated.  Pointers may initially be
5055 				 * NULL.
5056 				 */
5057     TileTypeBitMask *layers;	/* CIF layers to generate. */
5058     bool replace;		/* TRUE means that the new CIF is to replace
5059 				 * anything that was previously in planes.
5060 				 * FALSE means that the new CIF is to be
5061 				 * OR'ed in with the current contents of
5062 				 * planes.
5063 				 */
5064     bool genAllPlanes;		/* If TRUE, generate a tile plane even for
5065 				 * those layers not specified as being
5066 				 * generated in the 'layers' mask above.
5067 				 */
5068     bool hier;			/* TRUE if called from CIFGenSubcells or CIFGenArrays */
5069     ClientData clientdata;	/* Data that may be passed along to the
5070 				 * CIF operation functions.
5071 				 */
5072 {
5073     int i;
5074     Plane *new[MAXCIFLAYERS];
5075     Rect expanded, clip;
5076 
5077     /*
5078      * Generate the area in magic coordinates to search, and the area in
5079      * cif coordinates to use in clipping the results of CIFGenLayer().
5080      */
5081     cifGenClip(area, &expanded, &clip);
5082 
5083     /*
5084      * Generate all of the new layers in a temporary place.
5085      * If a layer isn't being generated, leave new[i] set to
5086      * NULL to indicate this fact.
5087      */
5088     for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
5089     {
5090 	if (TTMaskHasType(layers,i))
5091 	{
5092 	    CIFErrorLayer = i;
5093 	    new[i] = CIFGenLayer(CIFCurStyle->cs_layers[i]->cl_ops,
5094 		    &expanded, cellDef, origDef, new, hier, clientdata);
5095 
5096 	    /* Clean up the non-manhattan geometry in the plane */
5097 	    if (CIFUnfracture) DBMergeNMTiles(new[i], &expanded,
5098 			(PaintUndoInfo *)NULL);
5099 	}
5100 	else if (genAllPlanes) new[i] = DBNewPlane((ClientData) TT_SPACE);
5101 	else new[i] = (Plane *) NULL;
5102     }
5103 
5104     /*
5105      * Now mask off all the unwanted material in the new layers, and
5106      * either OR them into the existing layers or replace the existing
5107      * material with them.
5108      */
5109     for (i = 0; i < CIFCurStyle->cs_nLayers; i += 1)
5110     {
5111 	if (new[i])
5112 	    cifClipPlane(new[i], &clip);
5113 
5114 	if (replace)
5115 	{
5116 	    if (planes[i])
5117 	    {
5118 		DBFreePaintPlane(planes[i]);
5119 		TiFreePlane(planes[i]);
5120 	    }
5121 	    planes[i] = new[i];
5122 	    continue;
5123 	}
5124 
5125 	if (planes[i])
5126 	{
5127 	    if (new[i])
5128 	    {
5129 		cifPlane = planes[i];
5130 		cifScale = 1;
5131 		(void) DBSrPaintArea((Tile *) NULL, new[i], &TiPlaneRect,
5132 			&CIFSolidBits, cifPaintFunc,
5133 			(ClientData) CIFPaintTable);
5134 		DBFreePaintPlane(new[i]);
5135 		TiFreePlane(new[i]);
5136 	    }
5137 	}
5138 	else planes[i] = new[i];
5139     }
5140 }
5141 
5142 /*
5143  * ----------------------------------------------------------------------------
5144  *
5145  * cifClipPlane --
5146  *
5147  * Erase the portions of the plane 'plane' that lie outside of 'clip'.
5148  *
5149  * Results:
5150  *	None.
5151  *
5152  * Side effects:
5153  *	See above.
5154  *
5155  * ----------------------------------------------------------------------------
5156  */
5157 
5158 void
cifClipPlane(plane,clip)5159 cifClipPlane(plane, clip)
5160     Plane *plane;
5161     Rect *clip;
5162 {
5163     Rect r;
5164 
5165     if (clip->r_xtop < TiPlaneRect.r_xtop)
5166     {
5167 	r = TiPlaneRect;
5168 	r.r_xbot = clip->r_xtop;
5169 	DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5170     }
5171     if (clip->r_ytop < TiPlaneRect.r_ytop)
5172     {
5173 	r = TiPlaneRect;
5174 	r.r_ybot = clip->r_ytop;
5175 	DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5176     }
5177     if (clip->r_xbot > TiPlaneRect.r_xbot)
5178     {
5179 	r = TiPlaneRect;
5180 	r.r_xtop = clip->r_xbot;
5181 	DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5182     }
5183     if (clip->r_ybot > TiPlaneRect.r_ybot)
5184     {
5185 	r = TiPlaneRect;
5186 	r.r_ytop = clip->r_ybot;
5187 	DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5188     }
5189 }
5190 
5191 /*
5192  * ----------------------------------------------------------------------------
5193  *
5194  * cifGenClip --
5195  *
5196  * Compute two new areas from the original area:  one ('expanded')
5197  * is expanded by a CIF halo and is used to determine how much of
5198  * the database to search to find what's relevant for CIF generation;
5199  * the other ('clip') is the CIF equivalent of area and is used to
5200  * clip the resulting CIF.  This code is tricky because area may run
5201  * off to infinity, and we have to be careful not to expand past infinity.
5202  *
5203  * Results:
5204  *	None.
5205  *
5206  * Side effects:
5207  *	Sets *expanded and *clip.
5208  *
5209  * ----------------------------------------------------------------------------
5210  */
5211 
5212 void
cifGenClip(area,expanded,clip)5213 cifGenClip(area, expanded, clip)
5214     Rect *area;			/* Any CIF overlapping this area (in coords
5215 				 * of cellDef) will be generated.  The CIF
5216 				 * will be clipped to this area.
5217 				 */
5218     Rect *expanded, *clip;
5219 {
5220     if (area->r_xbot > TiPlaneRect.r_xbot)
5221     {
5222 	clip->r_xbot = area->r_xbot * CIFCurStyle->cs_scaleFactor;
5223 	expanded->r_xbot = area->r_xbot - CIFCurStyle->cs_radius;
5224     }
5225     else clip->r_xbot = expanded->r_xbot = area->r_xbot;
5226     if (area->r_ybot > TiPlaneRect.r_ybot)
5227     {
5228 	clip->r_ybot = area->r_ybot * CIFCurStyle->cs_scaleFactor;
5229 	expanded->r_ybot = area->r_ybot - CIFCurStyle->cs_radius;
5230     }
5231     else clip->r_ybot = expanded->r_ybot = area->r_ybot;
5232     if (area->r_xtop < TiPlaneRect.r_xtop)
5233     {
5234 	clip->r_xtop = area->r_xtop * CIFCurStyle->cs_scaleFactor;
5235 	expanded->r_xtop = area->r_xtop + CIFCurStyle->cs_radius;
5236     }
5237     else clip->r_xtop = expanded->r_xtop = area->r_xtop;
5238     if (area->r_ytop < TiPlaneRect.r_ytop)
5239     {
5240 	clip->r_ytop = area->r_ytop * CIFCurStyle->cs_scaleFactor;
5241 	expanded->r_ytop = area->r_ytop + CIFCurStyle->cs_radius;
5242     }
5243     else clip->r_ytop = expanded->r_ytop = area->r_ytop;
5244 }
5245 
5246 /*
5247  * ----------------------------------------------------------------------------
5248  *
5249  * CIFClearPlanes --
5250  *
5251  * 	This procedure clears out a collection of CIF planes.
5252  *
5253  * Results:
5254  *	None.
5255  *
5256  * Side effects:
5257  *	Each of the planes in "planes" is re-initialized to point to
5258  *	an empty paint plane.
5259  *
5260  * ----------------------------------------------------------------------------
5261  */
5262 
5263 void
CIFClearPlanes(planes)5264 CIFClearPlanes(planes)
5265     Plane **planes;		/* Pointer to an array of MAXCIFLAYERS
5266 				 * planes.
5267 				 */
5268 {
5269     int i;
5270 
5271     for (i = 0; i < MAXCIFLAYERS; i++)
5272     {
5273 	if (planes[i] == NULL)
5274 	{
5275 	    planes[i] = DBNewPlane((ClientData) TT_SPACE);
5276 	}
5277 	else
5278 	{
5279 	    DBClearPaintPlane(planes[i]);
5280 	}
5281     }
5282 }
5283