1 /*
2  * DBcellsearch.c --
3  *
4  * Area searching which spans cell boundaries.
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcellsrch.c,v 1.7 2010/09/15 21:53:22 tim Exp $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "utils/magic.h"
27 #include "utils/malloc.h"
28 #include "utils/geometry.h"
29 #include "utils/geofast.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "database/database.h"
33 #include "database/databaseInt.h"
34 #include "dbwind/dbwind.h"
35 #include "textio/textio.h"
36 #include "utils/signals.h"
37 #include "windows/windows.h"
38 #include "utils/main.h"
39 #include "mzrouter/mzrouter.h"
40 
41 /* Quick hack for dbScalePlanes() access to the CIF/GDS paint table */
42 
43 #ifdef CIF_MODULE
44 extern PaintResultType CIFPaintTable[];
45 #endif
46 
47 /*
48  * The following structure is used to accumulate information about
49  * the types of tiles visible underneath a given point in the database.
50  */
51 struct seeTypesArg
52 {
53     TileTypeBitMask *saa_mask;	/* Mask of tile types seen in search */
54     Rect *saa_rect;		/* Search area in root coordinates */
55 };
56 
57 /*
58  *-----------------------------------------------------------------------------
59  *
60  * DBSrCellPlaneArea --
61  *
62  * Searches a CellDef's cell plane and calls function func() for each
63  * cell use found.
64  *
65  * func() must be in the form:
66  *
67  *	int func(CellUse *use, ClientData cdata)
68  *
69  * and must return 0 to keep the search running, or 1 to end the search.
70  *
71  * Replaces the original TiSrArea() routine, but with the function's
72  * first argument as a CellUse pointer rather than a Tile pointer,
73  * since the tile plane has been replaced with the BPlane method.
74  *
75  * Returns 1 if the func() returns 1;  otherwise returns 0 to keep the
76  * search alive.
77  *
78  *-----------------------------------------------------------------------------
79  */
80 
81 int
DBSrCellPlaneArea(BPlane * plane,Rect * rect,int (* func)(),ClientData arg)82 DBSrCellPlaneArea(BPlane *plane, Rect *rect, int (*func)(), ClientData arg)
83 {
84     BPEnum bpe;
85     CellUse *use;
86     int rval = 0;
87 
88     BPEnumInit(&bpe, plane, rect, BPE_OVERLAP, "DBSrCellPlaneArea");
89 
90     while (use = BPEnumNext(&bpe))
91     {
92 	if ((*func)(use, arg))
93 	{
94 	    rval = 1;
95 	    break;
96 	}
97     }
98 
99     BPEnumTerm(&bpe);
100     return rval;
101 }
102 
103 /*
104  *-----------------------------------------------------------------------------
105  *
106  * DBTreeSrTiles --
107  *
108  * Recursively search downward from the supplied CellUse for
109  * all visible paint tiles matching the supplied type mask.
110  *
111  * The procedure should be of the following form:
112  *	int
113  *	func(tile, cxp)
114  *	    Tile *tile;
115  *	    TreeContext *cxp;
116  *	{
117  *	}
118  *
119  * The SearchContext is stored in cxp->tc_scx, and the user's arg is stored
120  * in cxp->tc_filter->tf_arg.
121  *
122  * In the above, the scx transform is the net transform from the coordinates
123  * of tile to "world" coordinates (or whatever coordinates the initial
124  * transform supplied to DBTreeSrTiles was a transform to).  Func returns
125  * 0 under normal conditions.  If 1 is returned, it is a request to
126  * abort the search.
127  *
128  *			*** WARNING ***
129  *
130  * The client procedure should not modify any of the paint planes in
131  * the cells visited by DBTreeSrTiles, because we use DBSrPaintArea
132  * as our paint-tile enumeration function.
133  *
134  * Results:
135  *	0 is returned if the search finished normally.  1 is returned
136  *	if the search was aborted.
137  *
138  * Side effects:
139  *	Whatever side effects are brought about by applying the
140  *	procedure supplied.
141  *
142  *-----------------------------------------------------------------------------
143  */
144 
145 int
DBTreeSrTiles(scx,mask,xMask,func,cdarg)146 DBTreeSrTiles(scx, mask, xMask, func, cdarg)
147     SearchContext *scx;		/* Pointer to search context specifying
148 				 * a cell use to search, an area in the
149 				 * coordinates of the cell's def, and a
150 				 * transform back to "root" coordinates.
151 				 */
152     TileTypeBitMask *mask;	/* Only tiles with a type for which
153 				 * a bit in this mask is on are processed.
154 				 */
155     int xMask;			/* All subcells are visited recursively
156 				 * until we encounter uses whose flags,
157 				 * when anded with xMask, are not
158 				 * equal to xMask.
159 				 */
160     int (*func)();		/* Function to apply at each qualifying tile */
161     ClientData cdarg;		/* Client data for above function */
162 {
163     int dbCellPlaneSrFunc();
164     TreeFilter filter;
165 
166     /* Set up the filter and call the recursive filter function */
167 
168     filter.tf_func = func;
169     filter.tf_arg = cdarg;
170     filter.tf_mask = mask;
171     filter.tf_xmask = xMask;
172     filter.tf_dinfo = 0;
173     filter.tf_planes = DBTechTypesToPlanes(mask);
174 
175     return dbCellPlaneSrFunc(scx, &filter);
176 }
177 
178 /*
179  * DBTreeSrNMTiles --
180  *	This is a variant of the above in which the search is over
181  *	a non-Manhattan area.
182  */
183 
184 int
DBTreeSrNMTiles(scx,dinfo,mask,xMask,func,cdarg)185 DBTreeSrNMTiles(scx, dinfo, mask, xMask, func, cdarg)
186     SearchContext *scx;		/* Pointer to search context specifying
187 				 * a cell use to search, an area in the
188 				 * coordinates of the cell's def, and a
189 				 * transform back to "root" coordinates.
190 				 */
191     TileType dinfo;		/* Type containing information about the
192 				 * diagonal area to search.
193 				 */
194     TileTypeBitMask *mask;	/* Only tiles with a type for which
195 				 * a bit in this mask is on are processed.
196 				 */
197     int xMask;			/* All subcells are visited recursively
198 				 * until we encounter uses whose flags,
199 				 * when anded with xMask, are not
200 				 * equal to xMask.
201 				 */
202     int (*func)();		/* Function to apply at each qualifying tile */
203     ClientData cdarg;		/* Client data for above function */
204 {
205     int dbCellPlaneSrFunc();
206     TreeFilter filter;
207 
208     /* Set up the filter and call the recursive filter function */
209 
210     filter.tf_func = func;
211     filter.tf_arg = cdarg;
212     filter.tf_mask = mask;
213     filter.tf_xmask = xMask;
214     filter.tf_dinfo = dinfo;
215     filter.tf_planes = DBTechTypesToPlanes(mask);
216 
217     return dbCellPlaneSrFunc(scx, &filter);
218 }
219 
220 /*
221  * dbCellPlaneSrFunc --
222  *
223  * Recursive filter procedure applied to the cell by DBTreeSrTiles().
224  */
225 
226 int
dbCellPlaneSrFunc(scx,fp)227 dbCellPlaneSrFunc(scx, fp)
228     SearchContext *scx;
229     TreeFilter *fp;
230 {
231     TreeContext context;
232     CellDef *def = scx->scx_use->cu_def;
233     int pNum;
234 
235     ASSERT(def != (CellDef *) NULL, "dbCellPlaneSrFunc");
236     if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
237 	return 0;
238     if ((def->cd_flags & CDAVAILABLE) == 0)
239     {
240 	bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
241 	if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
242     }
243 
244     context.tc_scx = scx;
245     context.tc_filter = fp;
246 
247     /*
248      * Apply the function first to any of the tiles in the planes
249      * for this CellUse's CellDef that match the mask.
250      */
251 
252     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
253 	if (PlaneMaskHasPlane(fp->tf_planes, pNum))
254 	{
255 	    context.tc_plane = pNum;
256 	    if (fp->tf_dinfo & TT_DIAGONAL)
257 	    {
258 		// TileType dinfo = DBTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
259 		TileType dinfo = DBInvTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
260 		if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
261 			dinfo, &scx->scx_area, fp->tf_mask,
262 			fp->tf_func, (ClientData) &context))
263 		    return 1;
264 	    }
265 	    else if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
266 		    &scx->scx_area, fp->tf_mask,
267 		    fp->tf_func, (ClientData) &context))
268 		return 1;
269 	}
270 
271     /*
272      * Now apply ourselves recursively to each of the CellUses
273      * in our cell plane.
274      */
275 
276     if (DBCellSrArea(scx, dbCellPlaneSrFunc, (ClientData) fp))
277 	return 1;
278     else return 0;
279 }
280 
281 
282 /*
283  *-----------------------------------------------------------------------------
284  *
285  * DBTreeSrUniqueTiles --
286  *
287  * Recursively search downward from the supplied CellUse for
288  * all visible paint tiles matching the supplied type mask.
289  * This routine is like DBTreeSrTiles, above, except that it will
290  * only call the specified routine ONCE for each contact type, in
291  * the home plane of that contact type.  Stacked contact types will
292  * only be processed if the current search plane matches the home
293  * plane of one of the stacked contact type's residues.
294  *
295  * Results:
296  *	0 is returned if the search finished normally.  1 is returned
297  *	if the search was aborted.
298  *
299  * Side effects:
300  *	Whatever side effects are brought about by applying the
301  *	procedure supplied.
302  *
303  *-----------------------------------------------------------------------------
304  */
305 
306 int
DBTreeSrUniqueTiles(scx,mask,xMask,func,cdarg)307 DBTreeSrUniqueTiles(scx, mask, xMask, func, cdarg)
308     SearchContext *scx;		/* Pointer to search context specifying
309 				 * a cell use to search, an area in the
310 				 * coordinates of the cell's def, and a
311 				 * transform back to "root" coordinates.
312 				 */
313     TileTypeBitMask *mask;	/* Only tiles with a type for which
314 				 * a bit in this mask is on are processed.
315 				 */
316     int xMask;			/* All subcells are visited recursively
317 				 * until we encounter uses whose flags,
318 				 * when anded with xMask, are not
319 				 * equal to xMask.
320 				 */
321     int (*func)();		/* Function to apply at each qualifying tile */
322     ClientData cdarg;		/* Client data for above function */
323 {
324     int dbCellPlaneSrFunc();
325     TreeFilter filter;
326 
327     /* Set up the filter and call the recursive filter function */
328 
329     filter.tf_func = func;
330     filter.tf_arg = cdarg;
331     filter.tf_mask = mask;
332     filter.tf_xmask = xMask;
333     filter.tf_planes = DBTechTypesToPlanes(mask);
334 
335     return dbCellUniqueTileSrFunc(scx, &filter);
336 }
337 
338 /*
339  * dbCellUniqueTileSrFunc --
340  *
341  * Recursive filter procedure applied to the cell by DBTreeSrUniqueTiles().
342  * This is similar to dbCellPlaneSrFunc, except that for each plane searched,
343  * only the tile types having that plane as their home plane will be passed
344  * to the filter function.  Contacts will therefore be processed only once.
345  */
346 
347 int
dbCellUniqueTileSrFunc(scx,fp)348 dbCellUniqueTileSrFunc(scx, fp)
349     SearchContext *scx;
350     TreeFilter *fp;
351 {
352     TreeContext context;
353     TileTypeBitMask uMask;
354     CellDef *def = scx->scx_use->cu_def;
355     int pNum;
356 
357     ASSERT(def != (CellDef *) NULL, "dbCellUniqueTileSrFunc");
358     if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
359 	return 0;
360     if ((def->cd_flags & CDAVAILABLE) == 0)
361     {
362 	bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
363 	if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
364     }
365 
366     context.tc_scx = scx;
367     context.tc_filter = fp;
368 
369     /*
370      * Apply the function first to any of the tiles in the planes
371      * for this CellUse's CellDef that match the mask.
372      */
373 
374     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
375 	if (PlaneMaskHasPlane(fp->tf_planes, pNum))
376 	{
377 	    uMask = DBHomePlaneTypes[pNum];
378 	    TTMaskAndMask(&uMask, fp->tf_mask);
379 	    if (!TTMaskIsZero(&uMask))
380 	    {
381 		context.tc_plane = pNum;
382 	        if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
383 		    	&scx->scx_area, &uMask, fp->tf_func,
384 			(ClientData) &context))
385 		    return 1;
386 	    }
387 	}
388 
389     /*
390      * Now apply ourselves recursively to each of the CellUses
391      * in our tile plane.
392      */
393 
394     if (DBCellSrArea(scx, dbCellUniqueTileSrFunc, (ClientData) fp))
395 	return 1;
396     else return 0;
397 }
398 
399 
400 /*
401  *-----------------------------------------------------------------------------
402  *
403  * DBNoTreeSrTiles --
404  *
405  * NOTE: THIS PROCEDURE IS EXACTLY LIKE DBTreeSrTiles EXCEPT THAT IT DOES
406  * NOT SEARCH SUBCELLS.
407  *
408  * Searches the supplied CellUse (if expanded) for
409  * all visible paint tiles matching the supplied type mask.
410  *
411  * The procedure should be of the following form:
412  *	int
413  *	func(tile, cxp)
414  *	    Tile *tile;
415  *	    TreeContext *cxp;
416  *	{
417  *	}
418  *
419  * The SearchContext is stored in cxp->tc_scx, and the user's arg is stored
420  * in cxp->tc_filter->tf_arg.
421  *
422  * In the above, the scx transform is the net transform from the coordinates
423  * of tile to "world" coordinates (or whatever coordinates the initial
424  * transform supplied to DBTreeSrTiles was a transform to).  Func returns
425  * 0 under normal conditions.  If 1 is returned, it is a request to
426  * abort the search.
427  *
428  *			*** WARNING ***
429  *
430  * The client procedure should not modify any of the paint planes in
431  * the cells visited by DBTreeSrTiles, because we use DBSrPaintArea
432  * as our paint-tile enumeration function.
433  *
434  * Results:
435  *	0 is returned if the search finished normally.  1 is returned
436  *	if the search was aborted.
437  *
438  * Side effects:
439  *	Whatever side effects are brought about by applying the
440  *	procedure supplied.
441  *
442  *-----------------------------------------------------------------------------
443  */
444 int
DBNoTreeSrTiles(scx,mask,xMask,func,cdarg)445 DBNoTreeSrTiles(scx, mask, xMask, func, cdarg)
446     SearchContext *scx;		/* Pointer to search context specifying
447 				 * a cell use to search, an area in the
448 				 * coordinates of the cell's def, and a
449 				 * transform back to "root" coordinates.
450 				 */
451     TileTypeBitMask *mask;	/* Only tiles with a type for which
452 				 * a bit in this mask is on are processed.
453 				 */
454     int xMask;			/* All subcells are visited recursively
455 				 * until we encounter uses whose flags,
456 				 * when anded with xMask, are not
457 				 * equal to xMask.
458 				 */
459     int (*func)();		/* Function to apply at each qualifying tile */
460     ClientData cdarg;		/* Client data for above function */
461 {
462     TreeContext context;
463     TreeFilter filter;
464     CellUse *cellUse = scx->scx_use;
465     CellDef *def = cellUse->cu_def;
466     int pNum;
467 
468     ASSERT(def != (CellDef *) NULL, "DBNoTreeSrTiles");
469     if (!DBDescendSubcell(cellUse, xMask))
470 	return 0;
471 
472     if ((def->cd_flags & CDAVAILABLE) == 0)
473     {
474 	bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
475 	if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
476     }
477 
478     filter.tf_func = func;
479     filter.tf_arg = cdarg;
480     filter.tf_mask = mask;
481     filter.tf_xmask = xMask;
482     filter.tf_planes = DBTechTypesToPlanes(mask);
483 
484     context.tc_scx = scx;
485     context.tc_filter = &filter;
486 
487     /*
488      * Apply the function first to any of the tiles in the planes
489      * for this CellUse's CellDef that match the mask.
490      */
491 
492     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
493 	if (PlaneMaskHasPlane(filter.tf_planes, pNum))
494 	{
495 	    if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
496 		    &scx->scx_area, mask, func, (ClientData) &context))
497 		return 1;
498 	}
499 
500     /* Return normally */
501     return 0;
502 }
503 
504 
505 /*
506  *-----------------------------------------------------------------------------
507  *
508  * DBTreeSrLabels --
509  *
510  * Recursively search downward from the supplied CellUse for
511  * all visible labels attached to layers matching the supplied
512  * type mask.
513  *
514  * The procedure should be of the following form:
515  *	int
516  *	func(scx, label, tpath, cdarg)
517  *	    SearchContext *scx;
518  *	    Label *label;
519  *	    TerminalPath *tpath;
520  *	    ClientData cdarg;
521  *	{
522  *	}
523  *
524  * In the above, the use associated with scx is the parent of the
525  * CellDef containing the tile which contains the label, and the
526  * transform associated is the net transform from the coordinates
527  * of the tile to "root" coordinates.  Func normally returns 0.  If
528  * func returns 1, it is a request to abort the search without finding
529  * any more labels.
530  *
531  * Results:
532  *	0 is returned if the search terminated normally.  1 is returned
533  *	if the search was aborted.
534  *
535  * Side effects:
536  *	Whatever side effects are brought about by applying the
537  *	procedure supplied.
538  *
539  *-----------------------------------------------------------------------------
540  */
541 
542 int
DBTreeSrLabels(scx,mask,xMask,tpath,flags,func,cdarg)543 DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
544     SearchContext *scx;		/* Pointer to search context specifying
545 				 * a cell use to search, an area in the
546 				 * coordinates of the cell's def, and a
547 				 * transform back to "root" coordinates.
548 				 * The area may have zero size.  Labels
549 				 * need only touch the area.
550 				 */
551     TileTypeBitMask * mask;	/* Only visit labels attached to these types */
552     int xMask;			/* All subcells are visited recursively
553 				 * until we encounter uses whose flags,
554 				 * when anded with xMask, are not
555 				 * equal to xMask.
556 				 */
557     TerminalPath *tpath;	/* Pointer to a structure describing a
558 				 * partially filled in terminal pathname.
559 				 * If this pointer is NULL, we don't bother
560 				 * filling it in further; otherwise, we add
561 				 * new pathname components as we encounter
562 				 * them.
563 				 */
564     unsigned char flags;	/* Flags to denote whether labels should be
565 				 * searched according to the area of the
566 				 * attachment, the area of the label itself,
567 				 * or both.
568 				 */
569     int (*func)();		/* Function to apply at each qualifying tile */
570     ClientData cdarg;		/* Client data for above function */
571 {
572     SearchContext scx2;
573     Label *lab;
574     Rect *r = &scx->scx_area;
575     CellUse *cellUse = scx->scx_use;
576     CellDef *def = cellUse->cu_def;
577     TreeFilter filter;
578     bool is_touching;
579     int dbCellLabelSrFunc();
580 
581     ASSERT(def != (CellDef *) NULL, "DBTreeSrLabels");
582     if (!DBDescendSubcell(cellUse, xMask)) return 0;
583     if ((def->cd_flags & CDAVAILABLE) == 0)
584     {
585 	bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
586 	if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
587     }
588 
589     for (lab = def->cd_labels; lab; lab = lab->lab_next)
590     {
591 	if (SigInterruptPending) break;
592 	is_touching = FALSE;
593 
594 	if ((lab->lab_font < 0) || (flags & TF_LABEL_ATTACH))
595 	{
596 	    /* For non-manhattan searches, label must be in or	*/
597 	    /* touch the triangle.  (to-do:  needs a proper	*/
598 	    /* insideness test)					*/
599 
600 	    if (flags & TF_LABEL_ATTACH_CORNER)
601 	    {
602 		Rect r1 = *r;
603 		Rect r2 = *r;
604 		if (flags & TF_LABEL_ATTACH_NOT_NE)
605 		{
606 		    r1.r_ytop = r->r_ybot;
607 		    r2.r_xtop = r->r_xbot;
608 		}
609 		else if (flags & TF_LABEL_ATTACH_NOT_NW)
610 		{
611 		    r1.r_ytop = r->r_ybot;
612 		    r2.r_xbot = r->r_xtop;
613 		}
614 		else if (flags & TF_LABEL_ATTACH_NOT_SE)
615 		{
616 		    r1.r_ybot = r->r_ytop;
617 		    r2.r_xtop = r->r_xbot;
618 		}
619 		else if (flags & TF_LABEL_ATTACH_NOT_SW)
620 		{
621 		    r1.r_ybot = r->r_ytop;
622 		    r2.r_xbot = r->r_xtop;
623 		}
624 		is_touching = GEO_TOUCH(&lab->lab_bbox, &r1) ||
625 			  GEO_TOUCH(&lab->lab_bbox, &r2);
626 	    }
627 	    else
628 		is_touching = GEO_TOUCH(&lab->lab_rect, r);
629 	}
630 	if (!is_touching && (flags & TF_LABEL_DISPLAY) && lab->lab_font >= 0)
631 	{
632 	    /* Check against bounds of the rendered label text */
633 	    is_touching = GEO_TOUCH(&lab->lab_bbox, r);
634 	}
635 
636 	if (is_touching && TTMaskHasType(mask, lab->lab_type))
637 	    if ((*func)(scx, lab, tpath, cdarg))
638 		return (1);
639     }
640 
641     filter.tf_func = func;
642     filter.tf_arg = cdarg;
643     filter.tf_mask = mask;
644     filter.tf_xmask = xMask;
645     filter.tf_tpath = tpath;
646     filter.tf_flags = flags;
647     /* filter.tf_planes is unused */
648 
649     /* Visit each child CellUse recursively.
650      * This code is a bit tricky because the area can have zero size.
651      * This would cause subcells never to be examined.  What we do is
652      * to expand the area by 1 here, then require the labels to OVERLAP
653      * instead of just TOUCH.  Be careful when expanding:  can't expand
654      * any coordinate past infinity.
655      */
656 
657     scx2 = *scx;
658     if (scx2.scx_area.r_xbot > TiPlaneRect.r_xbot) scx2.scx_area.r_xbot -= 1;
659     if (scx2.scx_area.r_ybot > TiPlaneRect.r_ybot) scx2.scx_area.r_ybot -= 1;
660     if (scx2.scx_area.r_xtop < TiPlaneRect.r_xtop) scx2.scx_area.r_xtop += 1;
661     if (scx2.scx_area.r_ytop < TiPlaneRect.r_ytop) scx2.scx_area.r_ytop += 1;
662     if (DBCellSrArea(&scx2, dbCellLabelSrFunc, (ClientData) &filter))
663 	return 1;
664 
665     return 0;
666 }
667 
668 
669 /*
670  * dbCellLabelSrFunc --
671  *
672  * Filter procedure applied to subcells by DBTreeSrLabels().
673  */
674 
675 int
dbCellLabelSrFunc(scx,fp)676 dbCellLabelSrFunc(scx, fp)
677     SearchContext *scx;
678     TreeFilter *fp;
679 {
680     Label *lab;
681     Rect *r = &scx->scx_area;
682     TileTypeBitMask *mask = fp->tf_mask;
683     CellDef *def = scx->scx_use->cu_def;
684     char *tnext;
685     int result;
686     bool has_overlap;
687 
688     ASSERT(def != (CellDef *) NULL, "dbCellLabelSrFunc");
689     if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask)) return 0;
690     if ((def->cd_flags & CDAVAILABLE) == 0)
691     {
692 	bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
693 	if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
694     }
695 
696     if (fp->tf_tpath != (TerminalPath *) NULL)
697     {
698 	TerminalPath *tp = fp->tf_tpath;
699 
700 	tnext = tp->tp_next;
701 	tp->tp_next = DBPrintUseId(scx, tp->tp_next, tp->tp_last-tp->tp_next,
702 			FALSE);
703 	if (tp->tp_next < tp->tp_last)
704 	{
705 	    *(tp->tp_next++) = '/';
706 	    *(tp->tp_next) = '\0';
707 	}
708     }
709 
710     /* Apply the function first to any of the labels in this def. */
711 
712     result = 0;
713     for (lab = def->cd_labels; lab; lab = lab->lab_next)
714     {
715 	has_overlap = FALSE;
716 	if ((lab->lab_font < 0) || (fp->tf_flags & TF_LABEL_ATTACH))
717 	    has_overlap = GEO_OVERLAP(&lab->lab_rect, r);
718 	if (!has_overlap && (fp->tf_flags & TF_LABEL_DISPLAY) && (lab->lab_font >= 0))
719 	    has_overlap = GEO_OVERLAP(&lab->lab_bbox, r);
720 
721 	if (has_overlap && TTMaskHasType(mask, lab->lab_type))
722 	{
723 	    if ((*fp->tf_func)(scx, lab, fp->tf_tpath, fp->tf_arg))
724 	    {
725 		result = 1;
726 		goto cleanup;
727 	    }
728 	}
729     }
730 
731     /* Now visit each child use recursively */
732     if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
733 	result = 1;
734 
735 cleanup:
736     /* Remove the trailing pathname component from the TerminalPath */
737     if (fp->tf_tpath != (TerminalPath *) NULL)
738     {
739 	fp->tf_tpath->tp_next = tnext;
740 	*tnext = '\0';
741     }
742 
743     return (result);
744 }
745 
746 /*
747  *-----------------------------------------------------------------------------
748  *
749  * DBTreeSrCells --
750  *
751  * Recursively search downward from the supplied CellUse for
752  * all CellUses whose parents are expanded but which themselves
753  * are unexpanded.
754  *
755  * The procedure should be of the following form:
756  *	int
757  *	func(scx, cdarg)
758  *	    SearchContext *scx;
759  *	    ClientData cdarg;
760  *	{
761  *	}
762  *
763  * In the above, the transform scx->scx_trans is from coordinates of
764  * the def of scx->scx_use to the "root".  The array indices
765  * scx->scx_x and scx->scx_y identify this element if it is a
766  * component of an array.  Func normally returns 0.  If func returns
767  * 1, then the search is aborted.  If func returns 2, then all
768  * remaining elements of the current array are skipped, but the
769  * search is not aborted.
770  *
771  * NOTE:  Unlike DBTreeSrTiles and DBTreeSrLabels, the function is not
772  * applied to the top level cell, only to descendents.
773  *
774  * Each element of an array is returned separately.
775  *
776  * Results:
777  *	0 is returned if the search terminated normally.  1 is
778  *	returned if it was aborted.
779  *
780  * Side effects:
781  *	Whatever side effects are brought about by applying the
782  *	procedure supplied.
783  *
784  *-----------------------------------------------------------------------------
785  */
786 
787 int
DBTreeSrCells(scx,xMask,func,cdarg)788 DBTreeSrCells(scx, xMask, func, cdarg)
789     SearchContext *scx;	/* Pointer to search context specifying a cell use to
790 			 * search, an area in the coordinates of the cell's
791 			 * def, and a transform back to "root" coordinates.
792 			 */
793     int xMask;		/* All subcells are visited recursively until we
794 			 * encounter uses whose flags, when anded with
795 			 * xMask, are not equal to xMask.  Func is called
796 			 * for these cells.  A zero mask means all cells in
797 			 * the root use are considered not to be expanded,
798 			 * and hence are passed to func.
799 			 */
800     int (*func)();	/* Function to apply to each qualifying cell */
801     ClientData cdarg;	/* Client data for above function */
802 {
803     int dbTreeCellSrFunc();
804     CellUse *cellUse = scx->scx_use;
805     TreeContext context;
806     TreeFilter filter;
807 
808     if (!DBDescendSubcell(cellUse, xMask))
809 	return 0;
810     if ((cellUse->cu_def->cd_flags & CDAVAILABLE) == 0)
811     {
812 	bool dereference = (cellUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
813 	if (!DBCellRead(cellUse->cu_def, (char *) NULL, TRUE, dereference, NULL))
814 	    return 0;
815     }
816 
817     context.tc_scx = scx;
818     context.tc_filter = &filter;
819 
820     filter.tf_func = func;
821     filter.tf_arg = cdarg;
822     filter.tf_xmask = xMask;
823 
824     if (DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) &filter))
825 	return 1;
826     else return 0;
827 }
828 
829 /*
830  * dbTreeCellSrFunc --
831  *
832  * Filter procedure applied to subcells by DBTreeSrCells().
833  */
834 
835     /*ARGSUSED*/
836 int
dbTreeCellSrFunc(scx,fp)837 dbTreeCellSrFunc(scx, fp)
838     SearchContext *scx;	/* Pointer to context containing a
839 					 * CellUse and a transform from coord-
840 					 * inates of the def of the use to the
841 					 * "root" of the search.
842 					 */
843     TreeFilter *fp;
844 {
845     CellUse *use = scx->scx_use;
846     int result;
847 
848     /* DBDescendSubcell treats a zero expand mask as "expanded everywhere",
849      * whereas we want it to mean "expanded nowhere".  Handle specially.
850      */
851 
852     if ((fp->tf_xmask == CU_DESCEND_NO_LOCK) && (use->cu_flags & CU_LOCKED))
853 	return 2;
854     else if (!DBDescendSubcell(use, fp->tf_xmask))
855 	return (*fp->tf_func)(scx, fp->tf_arg);
856     else
857     {
858 	if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
859 	{
860 	    bool dereference = (use->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
861 	    if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, dereference, NULL))
862 		return 0;
863 	}
864     }
865     if (fp->tf_xmask == CU_DESCEND_ALL)
866     {
867 	result = (*fp->tf_func)(scx, fp->tf_arg);
868 	if (result != 0) return result;
869     }
870 
871     /* Run recursively on children in search area */
872     return DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) fp);
873 }
874 
875 /*
876  *-----------------------------------------------------------------------------
877  *
878  * DBSeeTypesAll --
879  *
880  * Set a TileTypeBitMask of all visible tiles beneath the given rectangle.
881  * "Beneath" in this case means "completely containing".
882  * The search takes place recursively down to all expanded cells beneath
883  * rootUse.
884  *
885  * Results:
886  *	None.
887  *
888  * Side effects:
889  *	Sets the TileTypeBitMask pointed to by 'mask' to all types beneath
890  *	the rectangle.
891  *
892  *-----------------------------------------------------------------------------
893  */
894 
895 void
DBSeeTypesAll(rootUse,rootRect,xMask,mask)896 DBSeeTypesAll(rootUse, rootRect, xMask, mask)
897     CellUse *rootUse;	/* CellUse from which to begin search */
898     Rect *rootRect;	/* Clipping rectangle in coordinates of CellUse's def */
899     int xMask;		/* Expansion mask for DBTreeSrTiles() */
900     TileTypeBitMask *mask;	/* Mask to set */
901 {
902     int dbSeeTypesAllSrFunc();
903     SearchContext scontext;
904 
905     scontext.scx_use = rootUse;
906     scontext.scx_trans = GeoIdentityTransform;
907     scontext.scx_area = *rootRect;
908 
909     TTMaskZero(mask);
910     (void) DBTreeSrTiles(&scontext, &DBAllTypeBits, xMask,
911 		dbSeeTypesAllSrFunc, (ClientData) mask);
912 }
913 
914 /*
915  * dbSeeTypesAllSrFunc --
916  *
917  * Filter procedure applied to tiles by DBSeeTypesAll() above.
918  */
919 
920 int
dbSeeTypesAllSrFunc(tile,cxp)921 dbSeeTypesAllSrFunc(tile, cxp)
922     Tile *tile;
923     TreeContext *cxp;
924 {
925     Rect tileRect;
926     TileTypeBitMask *mask = (TileTypeBitMask *) cxp->tc_filter->tf_arg;
927     Rect *area = &cxp->tc_scx->scx_area;
928 
929     TiToRect(tile, &tileRect);
930     if (GEO_OVERLAP((&tileRect), area))
931     {
932 	if (IsSplit(tile))
933 	    TTMaskSetType(mask, SplitSide(tile) ?
934 			SplitRightType(tile) : SplitLeftType(tile));
935         else
936 	    TTMaskSetType(mask, TiGetType(tile));
937     }
938     return 0;
939 }
940 
941 /*
942  *-----------------------------------------------------------------------------
943  *
944  * DBSrRoots --
945  *
946  * Apply the supplied procedure to each CellUse that is a root of
947  * the given base CellDef.  A root is a CellUse with no parent def.
948  *
949  * The procedure should be of the following form:
950  *	int
951  *	func(cellUse, transform, cdarg)
952  *	    CellUse *cellUse;
953  *	    Transform *transform;
954  *	    ClientData cdarg;
955  *	{
956  *	}
957  *
958  * Transform is from coordinates of baseDef to those of the def of cellUse.
959  * Func normally returns 0.  If it returns 1 then the search is aborted.
960  *
961  * Results:
962  *	0 is returned if the search terminated normally.  1 is returned
963  *	if it was aborted.
964  *
965  * Side effects:
966  *	Whatever side effects are brought about by applying the
967  *	procedure supplied.
968  *
969  *-----------------------------------------------------------------------------
970  */
971 
972 int
DBSrRoots(baseDef,transform,func,cdarg)973 DBSrRoots(baseDef, transform, func, cdarg)
974     CellDef *baseDef;		/* Base CellDef, all of whose ancestors are
975 				 * searched for.
976 				 */
977     Transform *transform;	/* Transform from original baseDef to current
978 				 * baseDef.
979 				 */
980     int (*func)();		/* Function to apply at each root cellUse */
981     ClientData cdarg;		/* Client data for above function */
982 {
983     CellUse *parentUse;
984     int xoff, yoff, x, y;
985     Transform baseToParent, t;
986 
987     if (baseDef == (CellDef *) NULL)
988 	return 0;
989 
990     for (parentUse = baseDef->cd_parents;  parentUse != NULL;
991 	parentUse = parentUse->cu_nextuse)
992     {
993 	if (SigInterruptPending) return 1;
994 	if (parentUse->cu_parent == (CellDef *) NULL)
995 	{
996 	    GeoTransTrans(transform, &parentUse->cu_transform, &baseToParent);
997 	    if ((*func)(parentUse, &baseToParent, cdarg)) return 1;
998 	}
999 	else
1000 	{
1001 	    for (x = parentUse->cu_xlo; x <= parentUse->cu_xhi; x++)
1002 		for (y = parentUse->cu_ylo; y <= parentUse->cu_yhi; y++)
1003 		{
1004 		    if (SigInterruptPending)
1005 			return 1;
1006 
1007 		    xoff = (x - parentUse->cu_xlo) * parentUse->cu_xsep;
1008 		    yoff = (y - parentUse->cu_ylo) * parentUse->cu_ysep;
1009 		    GeoTranslateTrans(transform, xoff, yoff, &t);
1010 		    GeoTransTrans(&t, &parentUse->cu_transform, &baseToParent);
1011 		    if (DBSrRoots(parentUse->cu_parent, &baseToParent,
1012 			func, cdarg)) return 1;
1013 		}
1014 	}
1015     }
1016     return 0;
1017 }
1018 
1019 /*
1020  *-----------------------------------------------------------------------------
1021  *
1022  * DBIsAncestor --
1023  *
1024  * Determine if cellDef1 is an ancestor of cellDef2.
1025  *
1026  * Results:
1027  *	TRUE if cellDef1 is an ancestor of cellDef2, FALSE if not.
1028  *
1029  * Side effects:
1030  *	None.
1031  *
1032  *-----------------------------------------------------------------------------
1033  */
1034 
1035 bool
DBIsAncestor(cellDef1,cellDef2)1036 DBIsAncestor(cellDef1, cellDef2)
1037     CellDef *cellDef1;		/* Potential ancestor */
1038     CellDef *cellDef2;		/* Potential descendant -- this is where we
1039 				 * start the search.
1040 				 */
1041 {
1042     CellUse *parentUse;
1043     CellDef *parentDef;
1044 
1045     if (cellDef1 == cellDef2)
1046 	return (TRUE);
1047 
1048     for (parentUse = cellDef2->cd_parents;  parentUse != NULL;
1049 	parentUse = parentUse->cu_nextuse)
1050     {
1051 	if ((parentDef = parentUse->cu_parent) != (CellDef *) NULL)
1052 	    if (DBIsAncestor(cellDef1, parentDef))
1053 		return (TRUE);
1054     }
1055     return (FALSE);
1056 }
1057 
1058 /*
1059  *-----------------------------------------------------------------------------
1060  *
1061  * DBCellSrArea --
1062  *
1063  * Apply the supplied procedure to each of the cellUses found in the
1064  * given area in the subcell plane of the child def of the supplied
1065  * search context.
1066  *
1067  * The procedure is applied to each array element in each cell use that
1068  * overlaps the clipping rectangle.  The scx_x and scx_y parts of
1069  * the SearchContext passed to the filter function correspond to the
1070  * array element being visited.  The same CellUse is, of course, passed
1071  * as scx_use for all elements of the array.
1072  *
1073  * The array elements are visited by varying the X coordinate fastest.
1074  *
1075  * The procedure should be of the following form:
1076  *	int
1077  *	func(scx, cdarg)
1078  *	    SearchContext *scx;
1079  *	    ClientData cdarg;
1080  *	{
1081  *	}
1082  *
1083  * Func normally returns 0.  If it returns 1 then the search is
1084  * aborted.  If it returns 2, then any remaining elements in the
1085  * current array are skipped.
1086  *
1087  * Results:
1088  *	0 is returned if the search terminated normally.  1 is
1089  *	returned if it was aborted.
1090  *
1091  * Side effects:
1092  *	Whatever side effects are brought about by applying the
1093  *	procedure supplied.
1094  *
1095  *-----------------------------------------------------------------------------
1096  */
1097 
1098 int
DBCellSrArea(scx,func,cdarg)1099 DBCellSrArea(scx, func, cdarg)
1100     SearchContext *scx;
1101 			/* Pointer to search context specifying a cell use to
1102 			 * search, an area in the coordinates of the cell's
1103 			 * def, and a transform back to "root" coordinates.
1104 			 * The area may have zero size.
1105 			 */
1106     int (*func)();	/* Function to apply at every tile found */
1107     ClientData cdarg;	/* Argument to pass to function */
1108 {
1109     TreeFilter filter;
1110     TreeContext context;
1111     int dbCellSrFunc();
1112 
1113     filter.tf_func = func;
1114     filter.tf_arg = cdarg;
1115     context.tc_filter = &filter;
1116     context.tc_scx = scx;
1117 
1118     if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0)
1119     {
1120 	bool dereference = (scx->scx_use->cu_def->cd_flags & CDDEREFERENCE) ?
1121 		TRUE : FALSE;
1122 	if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, dereference, NULL))
1123 	    return 0;
1124     }
1125 
1126     if (DBSrCellPlaneArea(scx->scx_use->cu_def->cd_cellPlane,
1127 		&scx->scx_area, dbCellSrFunc, (ClientData) &context))
1128 	return 1;
1129     return 0;
1130 }
1131 
1132 /*
1133  *-----------------------------------------------------------------------------
1134  *
1135  * dbCellSrFunc --
1136  *
1137  * Filter procedure for DBCellSrArea.  Applies the procedure given
1138  * to DBCellSrArea to any of the CellUses in the given area.
1139  *
1140  * Results:
1141  *	0 is normally returned, and 1 is returned if an abort occurred.
1142  *
1143  * Side effects:
1144  *	Whatever side effects are brought about by applying the
1145  *	procedure supplied.
1146  *
1147  *-----------------------------------------------------------------------------
1148  */
1149 
1150 int
dbCellSrFunc(use,cxp)1151 dbCellSrFunc(use, cxp)
1152     CellUse *use;
1153     TreeContext *cxp;
1154 {
1155     TreeFilter *fp = cxp->tc_filter;
1156     SearchContext *scx = cxp->tc_scx;
1157     Rect *bbox;
1158     SearchContext newScx;
1159     Transform t, tinv;
1160     int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep, clientResult;
1161 
1162     bbox = &use->cu_bbox;
1163     newScx.scx_use = use;
1164 
1165     /* If not an array element, life is much simpler */
1166     if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi)
1167     {
1168 	newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi;
1169 	if (SigInterruptPending) return 1;
1170 	GEOINVERTTRANS(&use->cu_transform, &tinv);
1171 	GeoTransTrans(&use->cu_transform, &scx->scx_trans,
1172 				&newScx.scx_trans);
1173 	GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
1174 	if ((*fp->tf_func)(&newScx, fp->tf_arg) == 1)
1175 	    return 1;
1176 	return 0;
1177     }
1178 
1179     /*
1180      * More than a single array element;
1181      * check to see which ones overlap our search area.
1182      */
1183     DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi);
1184     xsep = (use->cu_xlo > use->cu_xhi) ? -use->cu_xsep : use->cu_xsep;
1185     ysep = (use->cu_ylo > use->cu_yhi) ? -use->cu_ysep : use->cu_ysep;
1186     for (newScx.scx_y = ylo; newScx.scx_y <= yhi; newScx.scx_y++)
1187         for (newScx.scx_x = xlo; newScx.scx_x <= xhi; newScx.scx_x++)
1188 	{
1189 	    if (SigInterruptPending) return 1;
1190 	    xbase = xsep * (newScx.scx_x - use->cu_xlo);
1191 	    ybase = ysep * (newScx.scx_y - use->cu_ylo);
1192 	    GeoTransTranslate(xbase, ybase, &use->cu_transform, &t);
1193 	    GEOINVERTTRANS(&t, &tinv);
1194 	    GeoTransTrans(&t, &scx->scx_trans, &newScx.scx_trans);
1195 	    GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
1196 	    clientResult = (*fp->tf_func)(&newScx, fp->tf_arg);
1197 	    if (clientResult == 2) return 0;
1198 	    else if (clientResult == 1) return 1;
1199 	}
1200 
1201     return 0;
1202 }
1203 
1204 /*
1205  *-----------------------------------------------------------------------------
1206  *
1207  * DBCellEnum --
1208  *
1209  * Apply the supplied procedure once to each CellUse in the subcell
1210  * plane of the supplied CellDef.  This procedure is not a geometric
1211  * search, but rather a hierarchical enumeration.  Use DBSrCellPlaneArea()
1212  * for geometric searches over an area.
1213  *
1214  * The procedure should be of the following form:
1215  *	int
1216  *	func(use, cdarg)
1217  *	    CellUse *use;
1218  *	    ClientData cdarg;
1219  *	{
1220  *	}
1221  *
1222  * Func returns 0 normally, 1 to abort the search.
1223  *
1224  * Results:
1225  *	0 if search terminated normally, 1 if it aborted.
1226  *
1227  * Side effects:
1228  *	Whatever side effects are brought about by applying the
1229  *	procedure supplied.
1230  *
1231  *-----------------------------------------------------------------------------
1232  */
1233 
1234 int
DBCellEnum(cellDef,func,cdarg)1235 DBCellEnum(cellDef, func, cdarg)
1236     CellDef *cellDef;	/* Def whose subcell plane is to be searched */
1237     int (*func)();	/* Function to apply at every tile found */
1238     ClientData cdarg;	/* Argument to pass to function */
1239 {
1240     TreeFilter filter;
1241     int dbEnumFunc();
1242 
1243     filter.tf_func = func;
1244     filter.tf_arg = cdarg;
1245     if ((cellDef->cd_flags & CDAVAILABLE) == 0)
1246     {
1247 	bool dereference = (cellDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
1248 	if (!DBCellRead(cellDef, (char *) NULL, TRUE, dereference, NULL)) return 0;
1249     }
1250     if (DBSrCellPlaneArea(cellDef->cd_cellPlane,
1251 		&TiPlaneRect, dbEnumFunc, (ClientData) &filter))
1252 	return 1;
1253     else return 0;
1254 }
1255 
1256 /*
1257  *-----------------------------------------------------------------------------
1258  *
1259  * dbEnumFunc --
1260  *
1261  * Filter procedure for DBCellEnum.  Applies the procedure given
1262  * to DBCellEnum to the visited CellUse.
1263  *
1264  * Results:
1265  *	0 normally, 1 if abort occurred.
1266  *
1267  * Side effects:
1268  *	Whatever side effects are brought about by applying the
1269  *	procedure supplied.
1270  *
1271  *-----------------------------------------------------------------------------
1272  */
1273 
1274 int
dbEnumFunc(use,fp)1275 dbEnumFunc(use, fp)
1276     CellUse *use;
1277     TreeFilter *fp;
1278 {
1279     Rect *bbox;
1280 
1281     bbox = &use->cu_bbox;
1282     if ((*fp->tf_func)(use, fp->tf_arg)) return 1;
1283     return 0;
1284 }
1285 
1286 /*
1287  * ----------------------------------------------------------------------------
1288  *
1289  * DBArraySr --
1290  *
1291  * 	Finds all elements of an array that fall in a particular area
1292  *	of the parent, and calls func for each element found.
1293  *
1294  *	The procedure should be of the following form:
1295  *	int
1296  *	func(cellUse, trans, x, y, cdarg)
1297  *	    CellUse *celluse;
1298  *	    Transform *trans;
1299  *	    int x, y;
1300  *	    ClientData cdarg;
1301  *	{}
1302  *
1303  *	In the above, cellUse is the original cellUse, trans is
1304  *	a transformation from the coordinates of the cell def to
1305  *	the coordinates of the use (for this array element), x and
1306  *	y are the indices of this array element, and cdarg is
1307  *	the ClientData supplied to us.	If 1 is returned by func,
1308  *	it is a signal to abort the search.
1309  *
1310  * Results:
1311  *	0 is returned if the search finished normally.  1 is returned
1312  *	if the search was aborted.
1313  *
1314  * Side effects:
1315  *	Whatever func does.
1316  *
1317  * ----------------------------------------------------------------------------
1318  */
1319 
1320 int
DBArraySr(use,searchArea,func,cdarg)1321 DBArraySr(use, searchArea, func, cdarg)
1322     CellUse *use;		/* CellUse of array to be searched. */
1323     Rect *searchArea;		/* Area of interest, given in the
1324 				 * coordinates of the parent (i.e. the
1325 				 * cell use, not def).  Must overlap
1326 				 * the array bounding box.
1327 				 */
1328     int (*func)();		/* Function to apply for each overlapping
1329 				 * array element.
1330 				 */
1331     ClientData cdarg;		/* Client-specific info to give to func. */
1332 {
1333     int xlo, xhi, ylo, yhi, x, y;
1334     int xsep, ysep, xbase, ybase;
1335     Transform t;
1336 
1337     DBArrayOverlap(use, searchArea, &xlo, &xhi, &ylo, &yhi);
1338     if (use->cu_xlo > use->cu_xhi) xsep = -use->cu_xsep;
1339     else xsep = use->cu_xsep;
1340     if (use->cu_ylo > use->cu_yhi) ysep = -use->cu_ysep;
1341     else ysep = use->cu_ysep;
1342     for (y = ylo; y <= yhi; y++)
1343 	for (x = xlo; x <= xhi; x++)
1344 	{
1345 	    if (SigInterruptPending) return 1;
1346 	    xbase = xsep * (x - use->cu_xlo);
1347 	    ybase = ysep * (y - use->cu_ylo);
1348 	    GeoTransTranslate(xbase, ybase, &use->cu_transform, &t);
1349 	    if ((*func)(use, &t, x, y, cdarg)) return 1;
1350 	}
1351     return 0;
1352 }
1353 
1354 /* Linked list structures for tile, celldef, and celluse enumeration */
1355 
1356 typedef struct LT1		/* A linked tile record */
1357 {
1358     Tile *tile;			/* Pointer to a tile */
1359     struct LT1 *t_next;		/* Pointer to another linked tile record */
1360 } LinkedTile;
1361 
1362 typedef struct LCD1		/* A linked celldef record */
1363 {
1364     CellDef *cellDef;		/* Pointer to a celldef */
1365     struct LCD1 *cd_next;	/* Pointer to another linked celldef record */
1366 } LinkedCellDef;
1367 
1368 typedef struct LCU1		/* A linked celluse record */
1369 {
1370     CellUse *cellUse;		/* Pointer to a celluse */
1371     struct LCU1 *cu_next;	/* Pointer to another linked celluse record */
1372 } LinkedCellUse;
1373 
1374 /*
1375  * ----------------------------------------------------------------------------
1376  *
1377  * DBMovePoint ---
1378  *
1379  *    Move a point by a position (origx, origy).  Ignore positions which
1380  *    are marked as (M)INFINITY.
1381  *
1382  * Results:
1383  *	TRUE if the point was moved (point position was not infinite)
1384  *
1385  * Side effects:
1386  *	Point structure pointed to by the first argument is repositioned.
1387  *
1388  * ----------------------------------------------------------------------------
1389  */
1390 
1391 bool
DBMovePoint(p,origx,origy)1392 DBMovePoint(p, origx, origy)
1393     Point *p;
1394     int origx, origy;
1395 {
1396     int result = FALSE;
1397     if ((p->p_x < (INFINITY - 2)) && (p->p_x > (MINFINITY + 2)))
1398     {
1399 	p->p_x -= origx;
1400 	result = TRUE;
1401     }
1402     if ((p->p_y < (INFINITY + 2)) && (p->p_y > (MINFINITY + 2)))
1403     {
1404 	p->p_y -= origy;
1405 	result = TRUE;
1406     }
1407     return result;
1408 }
1409 
1410 /*
1411  * ----------------------------------------------------------------------------
1412  *
1413  * DBScaleValue ---
1414  *
1415  *    Scale an integer by a factor of (scalen / scaled).  Always round down.
1416  *    this requires correcting integer arithmetic for negative numbers on
1417  *    the division step.  Values representing INFINITY are not scaled.
1418  *
1419  * Results:
1420  *	TRUE if the value does not scale exactly, FALSE otherwise.
1421  *
1422  * Side effects:
1423  *	Integer value passed as pointer is scaled, unless it represents
1424  *	an INFINITY measure.
1425  *
1426  * ----------------------------------------------------------------------------
1427  */
1428 
1429 bool
DBScaleValue(v,n,d)1430 DBScaleValue(v, n, d)
1431     int *v, n, d;
1432 {
1433     dlong llv = (dlong)(*v);
1434 
1435     if ((llv < (dlong)(INFINITY - 2)) && (llv > (dlong)(MINFINITY + 2)))
1436     {
1437 	llv *= (dlong)n;
1438 
1439 	if (llv > 0)
1440 	    llv /= (dlong)d;
1441 	else if (llv < 0)
1442 	    llv = ((llv + 1) / (dlong)d) - 1;
1443 	*v = (int)llv;
1444 
1445 	/* Hopefully we do not reach this error.  If we do, there's	*/
1446 	/* not much we can do about it except to increase Magic's	*/
1447 	/* internal Point structure to hold 8-byte integer values.	*/
1448 
1449 	if ((dlong)(*v) != llv)
1450 	    TxError("ERROR: ARITHMETIC OVERFLOW in DBScaleValue()!\n");
1451     }
1452     return (((*v) % d) != 0);
1453 }
1454 
1455 /*
1456  * ----------------------------------------------------------------------------
1457  *
1458  * DBScalePoint ---
1459  *
1460  *    Scale a point by a factor of (scalen / scaled).  Always round down.
1461  *    this requires correcting integer arithmetic for negative numbers on
1462  *    the division step.
1463  *
1464  * Results:
1465  *	TRUE if the point does not scale exactly, FALSE otherwise.
1466  *
1467  * Side effects:
1468  *	Point structure pointed to by the first argument is scaled.
1469  *
1470  * ----------------------------------------------------------------------------
1471  */
1472 
1473 bool
DBScalePoint(p,n,d)1474 DBScalePoint(p, n, d)
1475     Point *p;
1476     int n, d;
1477 {
1478     bool result;
1479     result = DBScaleValue(&p->p_x, n, d);
1480     result |= DBScaleValue(&p->p_y, n, d);
1481     return result;
1482 }
1483 
1484 /*
1485  * ----------------------------------------------------------------------------
1486  *
1487  * DBScaleEverything ---
1488  *
1489  *    Scale all geometry by a factor of (scalen / scaled).  This procedure
1490  *    cannot be undone!
1491  *
1492  * Results:
1493  *	None.
1494  *
1495  * Side Effects:
1496  *	Every single tile, label, and cell is altered.
1497  *	Geometry may be irrevocably distorted if transformed measurements
1498  *	would be sub-integer.  The MODIFIED flag is set on any cell for
1499  *	which any internal geometry does not scale precisely.
1500  *
1501  * ----------------------------------------------------------------------------
1502  */
1503 
1504 void
DBScaleEverything(scalen,scaled)1505 DBScaleEverything(scalen, scaled)
1506     int scalen, scaled;
1507 {
1508     void ToolScaleBox();
1509 
1510     int dbCellDefEnumFunc();
1511     LinkedCellDef *lhead, *lcd;
1512 
1513     // DBUpdateStamps();
1514 
1515     SigDisableInterrupts();
1516 
1517     lhead = NULL;
1518     (void) DBCellSrDefs(0, dbCellDefEnumFunc, (ClientData) &lhead);
1519 
1520     /* Apply scaling function to each CellDef */
1521 
1522     lcd = lhead;
1523     while (lcd != NULL)
1524     {
1525 	dbScaleCell(lcd->cellDef, scalen, scaled);
1526 	lcd = lcd->cd_next;
1527     }
1528 
1529     /* Free the linked CellDef list */
1530 
1531     lcd = lhead;
1532     while (lcd != NULL)
1533     {
1534 	freeMagic((char *)lcd);
1535 	lcd = lcd->cd_next;
1536     }
1537 
1538     /* Scale all elements */
1539     DBWScaleElements(scalen, scaled);
1540 
1541     /* Recovery of global plane pointers */
1542     MZAttachHintPlanes();
1543 
1544     /* Modify root box */
1545     ToolScaleBox(scalen, scaled);
1546 
1547     /* Modify crosshair position */
1548     DBWScaleCrosshair(scalen, scaled);
1549 
1550     SigEnableInterrupts();
1551 }
1552 
1553 /* Structure needed to hold information about the plane to copy */
1554 
1555 struct scaleArg {
1556    int scalen;
1557    int scaled;
1558    int pnum;
1559    Plane *ptarget;
1560    bool doCIF;
1561    bool modified;
1562 };
1563 
1564 struct moveArg {
1565    int origx;
1566    int origy;
1567    int pnum;
1568    Plane *ptarget;
1569    bool modified;
1570 };
1571 
1572 /*
1573  * ----------------------------------------------------------------------------
1574  *
1575  * dbScalePlane --
1576  *
1577  *   Scaling procedure called on a single plane.  Copies paint into the
1578  *   new plane at a scalefactor according to ratio (scalen / scaled)
1579  *
1580  * ----------------------------------------------------------------------------
1581  */
1582 
1583 bool
dbScalePlane(oldplane,newplane,pnum,scalen,scaled,doCIF)1584 dbScalePlane(oldplane, newplane, pnum, scalen, scaled, doCIF)
1585     Plane *oldplane, *newplane;
1586     int pnum;
1587     int scalen, scaled;
1588     bool doCIF;
1589 {
1590     int dbTileScaleFunc();		/* forward declaration */
1591     struct scaleArg arg;
1592 
1593     arg.scalen = scalen;
1594     arg.scaled = scaled;
1595     arg.ptarget = newplane;
1596     arg.pnum = pnum;
1597     arg.doCIF = doCIF;
1598     arg.modified = FALSE;
1599     (void) DBSrPaintArea((Tile *) NULL, oldplane, &TiPlaneRect,
1600 		&DBAllButSpaceBits, dbTileScaleFunc, (ClientData) &arg);
1601 
1602     return arg.modified;
1603 }
1604 
1605 /*
1606  * ----------------------------------------------------------------------------
1607  *
1608  * dbTileScaleFunc --
1609  *
1610  *   Scaling procedure called on each tile being copied from one plane to
1611  *   another.  Scaling ratio (scalen / scaled) is stored inside the struct
1612  *   scaleArg before calling.
1613  *
1614  * ----------------------------------------------------------------------------
1615  */
1616 
1617 int
dbTileScaleFunc(tile,scvals)1618 dbTileScaleFunc(tile, scvals)
1619     Tile *tile;
1620     struct scaleArg *scvals;
1621 {
1622     TileType type;
1623     Rect targetRect;
1624     TileType exact;
1625 
1626     TiToRect(tile, &targetRect);
1627 
1628     if (DBScalePoint(&targetRect.r_ll, scvals->scalen, scvals->scaled))
1629 	scvals->modified = TRUE;
1630     if (DBScalePoint(&targetRect.r_ur, scvals->scalen, scvals->scaled))
1631 	scvals->modified = TRUE;
1632 
1633     /* Tile scaled out of existence! */
1634     if ((targetRect.r_xtop - targetRect.r_xbot == 0) ||
1635 		(targetRect.r_ytop - targetRect.r_ybot == 0))
1636     {
1637 	TxPrintf("Tile 0x%x at (%d, %d) has zero area after scaling:  Removed.\n",
1638 		tile, targetRect.r_xbot, targetRect.r_ybot);
1639 	return 0;
1640     }
1641 
1642     type = TiGetTypeExact(tile);
1643     exact = type;
1644     if (IsSplit(tile))
1645 	type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
1646     DBNMPaintPlane(scvals->ptarget, exact, &targetRect,
1647 		((scvals->doCIF) ? CIFPaintTable :
1648 		DBStdPaintTbl(type, scvals->pnum)),
1649 		(PaintUndoInfo *)NULL);
1650     return 0;
1651 }
1652 
1653 /*
1654  * ----------------------------------------------------------------------------
1655  *
1656  * dbMovePlane --
1657  *
1658  *   Relocation procedure called on a single plane.  Copies paint into the
1659  *   new plane at a delta position (-origx, -origy)
1660  *
1661  * ----------------------------------------------------------------------------
1662  */
1663 
1664 bool
dbMovePlane(oldplane,newplane,pnum,origx,origy)1665 dbMovePlane(oldplane, newplane, pnum, origx, origy)
1666     Plane *oldplane, *newplane;
1667     int pnum;
1668     int origx, origy;
1669 {
1670     int dbTileMoveFunc();		/* forward declaration */
1671     struct moveArg arg;
1672 
1673     arg.origx = origx;
1674     arg.origy = origy;
1675     arg.ptarget = newplane;
1676     arg.pnum = pnum;
1677     arg.modified = FALSE;
1678     (void) DBSrPaintArea((Tile *) NULL, oldplane, &TiPlaneRect,
1679 		&DBAllButSpaceBits, dbTileMoveFunc, (ClientData) &arg);
1680 
1681     return arg.modified;
1682 }
1683 
1684 /*
1685  * ----------------------------------------------------------------------------
1686  *
1687  * dbTileMoveFunc --
1688  *
1689  *   Repositioning procedure called on each tile being copied from one plane
1690  *   to another.  Delta position (-origx, -origy) is stored inside the struct
1691  *   moveArg before calling.
1692  *
1693  * ----------------------------------------------------------------------------
1694  */
1695 
1696 int
dbTileMoveFunc(tile,mvvals)1697 dbTileMoveFunc(tile, mvvals)
1698     Tile *tile;
1699     struct moveArg *mvvals;
1700 {
1701     TileType type;
1702     Rect targetRect;
1703     TileType exact;
1704 
1705     TiToRect(tile, &targetRect);
1706 
1707     mvvals->modified = TRUE;
1708     DBMovePoint(&targetRect.r_ll, mvvals->origx, mvvals->origy);
1709     DBMovePoint(&targetRect.r_ur, mvvals->origx, mvvals->origy);
1710 
1711     type = TiGetTypeExact(tile);
1712     exact = type;
1713     if (IsSplit(tile))
1714 	type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
1715     DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
1716 		DBStdPaintTbl(type, mvvals->pnum),
1717 		(PaintUndoInfo *)NULL);
1718     return 0;
1719 }
1720 
1721 /*
1722  * ----------------------------------------------------------------------------
1723  *
1724  * DBSrCellUses --
1725  *
1726  *   Do function "func" for each cell use in cellDef, passing "arg" as
1727  *   client data.  This routine first collects a linked list of cell uses,
1728  *   then performs the function on the list, so that the search cannot be
1729  *   corrupted by (specifically) removing the use structure from the cell
1730  *   def's bplane.  Function "func" takes 2 arguments:
1731  *
1732  *	int func(Celluse *use, ClientData arg) {}
1733  *
1734  * Results:
1735  *	0 one successful completion of the search, 1 on error.
1736  *
1737  * Side Effects:
1738  *	Whatever "func" does.
1739  *
1740  * ----------------------------------------------------------------------------
1741  */
1742 
1743 int
DBSrCellUses(cellDef,func,arg)1744 DBSrCellUses(cellDef, func, arg)
1745     CellDef *cellDef;	/* Pointer to CellDef to search for uses. */
1746     int (*func)();	/* Function to apply for each cell use.	  */
1747     ClientData arg;	/* data to be passed to function func().  */
1748 {
1749     int dbCellUseEnumFunc();
1750     int retval;
1751     CellUse *use;
1752     LinkedCellUse *luhead, *lu;
1753 
1754     /* DBCellEnum() attempts to read unavailable celldefs.  We don't	*/
1755     /* want to do that here, so check CDAVAILABLE flag first.	  	*/
1756 
1757     if ((cellDef->cd_flags & CDAVAILABLE) == 0) return 0;
1758 
1759     /* Enumerate all unique cell uses, and scale their position,	*/
1760     /* transform, and array information.				*/
1761 
1762     luhead = NULL;
1763 
1764     retval = DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
1765 
1766     lu = luhead;
1767     while (lu != NULL)
1768     {
1769 	use = lu->cellUse;
1770 	if ((*func)(use, arg)) {
1771 	   retval = 1;
1772 	   break;
1773 	}
1774 	lu = lu->cu_next;
1775     }
1776 
1777     /* Free this linked cellUse structure */
1778     lu = luhead;
1779     while (lu != NULL)
1780     {
1781 	freeMagic((char *)lu);
1782 	lu = lu->cu_next;
1783     }
1784     return retval;
1785 }
1786 
1787 /* Structure used by dbScaleProp() and dbMoveProp() */
1788 typedef struct _cellpropstruct {
1789     Point cps_point;
1790     CellDef *cps_def;
1791 } CellPropStruct;
1792 
1793 /*
1794  * ----------------------------------------------------------------------------
1795  *
1796  * dbScaleProp --
1797  *
1798  *  Callback function for dbScaleCell.  Finds properties that represent
1799  *  internal geometry (FIXED_BBOX and MASKHINTS_*) and scale the values
1800  *  by the numerator / denominator values passed as a pointer to a Point
1801  *  structure, where p_x is the numerator value and p_y is the denominator
1802  *  value.
1803  *
1804  * ----------------------------------------------------------------------------
1805  */
1806 
dbScaleProp(name,value,cps)1807 int dbScaleProp(name, value, cps)
1808     char *name;
1809     char *value;
1810     CellPropStruct *cps;
1811 {
1812     int scalen, scaled;
1813     char *newvalue, *vptr;
1814     Rect r;
1815 
1816     if (!strcmp(name, "FIXED_BBOX"))
1817     {
1818 	if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
1819 			&r.r_xtop, &r.r_ytop) == 4)
1820 	{
1821 	    /* Scale numerator held in point X value, */
1822 	    /* scale denominator held in point Y value */
1823 
1824 	    scalen = cps->cps_point.p_x;
1825 	    scaled = cps->cps_point.p_y;
1826 
1827 	    DBScalePoint(&r.r_ll, scalen, scaled);
1828 	    DBScalePoint(&r.r_ur, scalen, scaled);
1829 
1830 	    newvalue = (char *)mallocMagic(40);
1831 	    sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
1832 			r.r_xtop, r.r_ytop);
1833 	    DBPropPut(cps->cps_def, name, newvalue);
1834 	}
1835     }
1836     else if (!strncmp(name, "MASKHINTS_", 10))
1837     {
1838 	char *vptr, *lastval;
1839 	int lastlen;
1840 
1841 	newvalue = (char *)NULL;
1842 	vptr = value;
1843 	while (*vptr != '\0')
1844 	{
1845 	    if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
1846 			&r.r_xtop, &r.r_ytop) == 4)
1847 	    {
1848 	    	/* Scale numerator held in point X value, */
1849 	    	/* scale denominator held in point Y value */
1850 
1851 	    	scalen = cps->cps_point.p_x;
1852 	    	scaled = cps->cps_point.p_y;
1853 
1854 	    	DBScalePoint(&r.r_ll, scalen, scaled);
1855 	    	DBScalePoint(&r.r_ur, scalen, scaled);
1856 
1857 		lastval = newvalue;
1858 		lastlen = (lastval) ? strlen(lastval) : 0;
1859 		newvalue = mallocMagic(40 + lastlen);
1860 
1861 		if (lastval)
1862 		    strcpy(newvalue, lastval);
1863 		else
1864 		    *newvalue = '\0';
1865 
1866 		sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
1867 			r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
1868 		if (lastval) freeMagic(lastval);
1869 
1870 		/* Parse through the four values and check if there's more */
1871                 while (*vptr && !isspace(*vptr)) vptr++;
1872                 while (*vptr && isspace(*vptr)) vptr++;
1873                 while (*vptr && !isspace(*vptr)) vptr++;
1874                 while (*vptr && isspace(*vptr)) vptr++;
1875                 while (*vptr && !isspace(*vptr)) vptr++;
1876                 while (*vptr && isspace(*vptr)) vptr++;
1877                 while (*vptr && !isspace(*vptr)) vptr++;
1878                 while (*vptr && isspace(*vptr)) vptr++;
1879 	    }
1880 	    else break;
1881 	}
1882 	if (newvalue)
1883 	    DBPropPut(cps->cps_def, name, newvalue);
1884     }
1885     return 0;	/* Keep enumerating through properties */
1886 }
1887 
1888 /*
1889  * ----------------------------------------------------------------------------
1890  *
1891  * dbMoveProp --
1892  *
1893  *  Callback function for ??.  Finds properties that represent
1894  *  internal geometry (FIXED_BBOX and MASKHINTS_*) and modifies the values
1895  *  by the X, Y values passed as a pointer to a Point structure in ClientData.
1896  *
1897  * ----------------------------------------------------------------------------
1898  */
1899 
dbMoveProp(name,value,cps)1900 int dbMoveProp(name, value, cps)
1901     char *name;
1902     char *value;
1903     CellPropStruct *cps;
1904 {
1905     int origx, origy;
1906     char *newvalue;
1907     Rect r;
1908 
1909     if (!strcmp(name, "FIXED_BBOX") || !strncmp(name, "MASKHINTS_", 10))
1910     {
1911 	if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
1912 			&r.r_xtop, &r.r_ytop) == 4)
1913 	{
1914 	    origx = cps->cps_point.p_x;
1915 	    origy = cps->cps_point.p_y;
1916 
1917 	    DBMovePoint(&r.r_ll, origx, origy);
1918 	    DBMovePoint(&r.r_ur, origx, origy);
1919 
1920 	    newvalue = (char *)mallocMagic(40);
1921 	    sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
1922 			r.r_xtop, r.r_ytop);
1923 	    DBPropPut(cps->cps_def, name, newvalue);
1924 	}
1925     }
1926     return 0;	/* Keep enumerating through properties */
1927 }
1928 
1929 
1930 /*
1931  * ----------------------------------------------------------------------------
1932  *
1933  * dbScaleCell --
1934  *
1935  *   Scaling procedure called on each cell encountered in the search.
1936  *
1937  * ----------------------------------------------------------------------------
1938  */
1939 
1940 int
dbScaleCell(cellDef,scalen,scaled)1941 dbScaleCell(cellDef, scalen, scaled)
1942     CellDef *cellDef;	/* Pointer to CellDef to be saved.  This def might
1943 			 * be an internal buffer; if so, we ignore it.
1944 			 */
1945     int scalen, scaled; /* scale numerator and denominator. */
1946 {
1947     int dbCellScaleFunc(), dbCellUseEnumFunc();
1948     Label *lab;
1949     int pNum;
1950     LinkedTile *lhead, *lt;
1951     LinkedCellUse *luhead, *lu;
1952     Plane *newplane;
1953     BPlane *cellPlane, *cellPlaneOrig;
1954     CellPropStruct cps;
1955 
1956     /* DBCellEnum() attempts to read unavailable celldefs.  We don't	*/
1957     /* want to do that here, so check CDAVAILABLE flag first.	  	*/
1958 
1959     if ((cellDef->cd_flags & CDAVAILABLE) == 0)
1960 	goto donecell;
1961     else
1962 	cellDef->cd_flags |= CDBOXESCHANGED;
1963 
1964     /* Enumerate all unique cell uses, and scale their position,	*/
1965     /* transform, and array information.				*/
1966 
1967     luhead = NULL;
1968 
1969     (void) DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
1970 
1971     cellPlane = BPNew();
1972     lu = luhead;
1973     while (lu != NULL)
1974     {
1975 	CellUse *use;
1976 	Rect *bbox;
1977 
1978 	use = lu->cellUse;
1979 	bbox = &use->cu_bbox;
1980 
1981 	/* TxPrintf("CellUse: BBox is ll (%d, %d), transform [%d %d %d %d %d %d]\n",
1982 		bbox->r_xbot, bbox->r_ybot,
1983 		use->cu_transform.t_a, use->cu_transform.t_b, use->cu_transform.t_c,
1984 		use->cu_transform.t_d, use->cu_transform.t_e, use->cu_transform.t_f); */
1985 
1986 	DBScalePoint(&bbox->r_ll, scalen, scaled);
1987 	DBScalePoint(&bbox->r_ur, scalen, scaled);
1988 
1989 	bbox = &use->cu_extended;
1990 	DBScalePoint(&bbox->r_ll, scalen, scaled);
1991 	DBScalePoint(&bbox->r_ur, scalen, scaled);
1992 
1993 	DBScaleValue(&use->cu_transform.t_c, scalen, scaled);
1994 	DBScaleValue(&use->cu_transform.t_f, scalen, scaled);
1995 
1996 	DBScaleValue(&use->cu_array.ar_xsep, scalen, scaled);
1997 	DBScaleValue(&use->cu_array.ar_ysep, scalen, scaled);
1998 
1999 	BPAdd(cellPlane, use);
2000 
2001 	lu = lu->cu_next;
2002     }
2003 
2004     /* Swap the CellDef's cell plane */
2005     cellPlaneOrig = cellDef->cd_cellPlane;
2006     cellDef->cd_cellPlane = cellPlane;
2007     BPFree(cellPlaneOrig);
2008 
2009     /* Free this linked cellUse structure */
2010     lu = luhead;
2011     while (lu != NULL)
2012     {
2013 	freeMagic((char *)lu);
2014 	lu = lu->cu_next;
2015     }
2016 
2017     /* Scale all of the paint tiles in this cell by creating a new plane */
2018     /* and copying all tiles into the new plane at scaled dimensions.	 */
2019 
2020     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
2021     {
2022 	if (cellDef->cd_planes[pNum] == NULL) continue;
2023 	newplane = DBNewPlane((ClientData) TT_SPACE);
2024 	DBClearPaintPlane(newplane);
2025 	if (dbScalePlane(cellDef->cd_planes[pNum], newplane, pNum,
2026 		scalen, scaled, FALSE))
2027 	    cellDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
2028         DBFreePaintPlane(cellDef->cd_planes[pNum]);
2029 	TiFreePlane(cellDef->cd_planes[pNum]);
2030         cellDef->cd_planes[pNum] = newplane;
2031     }
2032 
2033     /* Also scale the position of all labels. */
2034     /* If labels are the rendered-font type, scale the size as well */
2035 
2036     if (cellDef->cd_labels)
2037     {
2038 	int i;
2039 	for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
2040 	{
2041 	    DBScalePoint(&lab->lab_rect.r_ll, scalen, scaled);
2042 	    DBScalePoint(&lab->lab_rect.r_ur, scalen, scaled);
2043 
2044 	    if (lab->lab_font >= 0)
2045 	    {
2046 		DBScalePoint(&lab->lab_offset, scalen, scaled);
2047 		DBScaleValue(&lab->lab_size, scalen, scaled);
2048 
2049 		DBScalePoint(&lab->lab_bbox.r_ll, scalen, scaled);
2050 		DBScalePoint(&lab->lab_bbox.r_ur, scalen, scaled);
2051 
2052 		for (i = 0; i < 4; i++)
2053 		    DBScalePoint(&lab->lab_corners[i], scalen, scaled);
2054 	    }
2055 	}
2056     }
2057 
2058 donecell:
2059 
2060     /* The cellDef bounding box gets expanded to match the new scale. */
2061 
2062     DBScalePoint(&cellDef->cd_bbox.r_ll, scalen, scaled);
2063     DBScalePoint(&cellDef->cd_bbox.r_ur, scalen, scaled);
2064     DBScalePoint(&cellDef->cd_extended.r_ll, scalen, scaled);
2065     DBScalePoint(&cellDef->cd_extended.r_ur, scalen, scaled);
2066 
2067     /* If the cell is an abstract view with a fixed bounding box, then  */
2068     /* adjust the bounding box property to match the new scale.         */
2069 
2070     if ((cellDef->cd_flags & CDFIXEDBBOX) != 0)
2071     {
2072 	Rect r;
2073 	bool found;
2074 	char *propval;
2075 
2076 	propval = (char *)DBPropGet(cellDef, "FIXED_BBOX", &found);
2077 	if (found)
2078 	{
2079 	    if (sscanf(propval, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
2080 			&r.r_xtop, &r.r_ytop) == 4)
2081 	    {
2082 		DBScalePoint(&r.r_ll, scalen, scaled);
2083 		DBScalePoint(&r.r_ur, scalen, scaled);
2084 
2085 		propval = (char *)mallocMagic(40);
2086 		sprintf(propval, "%d %d %d %d", r.r_xbot, r.r_ybot,
2087 			r.r_xtop, r.r_ytop);
2088 		DBPropPut(cellDef, "FIXED_BBOX", propval);
2089 	    }
2090 	}
2091     }
2092 
2093     /* Check all properties for ones with keys beginning with "MASKHINTS_"
2094      * or the key "FIXED_BBOX", and scale them by the same amount as all
2095      * the geometry.
2096      */
2097 
2098 
2099     cps.cps_point.p_x = scalen;
2100     cps.cps_point.p_y = scaled;
2101     cps.cps_def = cellDef;
2102     DBPropEnum(cellDef, dbScaleProp, &cps);
2103 
2104     return 0;
2105 }
2106 
2107 /*
2108  * ----------------------------------------------------------------------------
2109  *
2110  * dbCellDefEnumFunc --
2111  *
2112  *   Enumeration procedure called on each CellDef encountered in the search of
2113  *   cells in the hierarchy.  Adds the CellDef to a linked list of celldefs.
2114  *
2115  * ----------------------------------------------------------------------------
2116  */
2117 
2118 int
dbCellDefEnumFunc(cellDef,arg)2119 dbCellDefEnumFunc(cellDef, arg)
2120     CellDef *cellDef;
2121     LinkedCellDef **arg;
2122 {
2123     LinkedCellDef *lcd;
2124 
2125     lcd = (LinkedCellDef *) mallocMagic(sizeof(LinkedCellDef));
2126 
2127     lcd->cellDef = cellDef;
2128     lcd->cd_next = (*arg);
2129     (*arg) = lcd;
2130 
2131     return 0;
2132 }
2133 
2134 /*
2135  * ----------------------------------------------------------------------------
2136  *
2137  * dbCellUseEnumFunc --
2138  *
2139  *   Enumeration procedure called on each CellDef encountered in the search of
2140  *   cells in the hierarchy.  Adds the CellDef to a linked list of celldefs.
2141  *
2142  * ----------------------------------------------------------------------------
2143  */
2144 
2145 int
dbCellUseEnumFunc(cellUse,arg)2146 dbCellUseEnumFunc(cellUse, arg)
2147     CellUse *cellUse;
2148     LinkedCellUse **arg;
2149 {
2150     LinkedCellUse *lcu;
2151 
2152     lcu = (LinkedCellUse *) mallocMagic(sizeof(LinkedCellUse));
2153 
2154     lcu->cellUse = cellUse;
2155     lcu->cu_next = (*arg);
2156     (*arg) = lcu;
2157 
2158     return 0;
2159 }
2160 
2161 /*
2162  * ----------------------------------------------------------------------------
2163  *
2164  * DBMoveCell --
2165  *
2166  *   Reposition a cell to a different origin.  This routine is equivalent to
2167  *   unexpanding all contents of a cell, selecting everything, and issuing a
2168  *   move command.  However, for very large layouts this becomes memory- and
2169  *   compute- intensive.  The process of reorienting an entire layout to a
2170  *   new position can be done much more efficiently.  This routine is
2171  *   essentially a copy of dbScaleCell() but changes only position and not
2172  *   scale.
2173  *
2174  * ----------------------------------------------------------------------------
2175  */
2176 
2177 int
DBMoveCell(cellDef,origx,origy)2178 DBMoveCell(cellDef, origx, origy)
2179     CellDef *cellDef;	/* Pointer to CellDef to be saved.  This def might
2180 			 * be an internal buffer; if so, we ignore it.
2181 			 */
2182     int origx, origy; /* Internal unit coordinates which will become the new origin */
2183 {
2184     int dbCellTileEnumFunc(), dbCellUseEnumFunc();
2185     Label *lab;
2186     int pNum;
2187     LinkedTile *lhead, *lt;
2188     LinkedCellUse *luhead, *lu;
2189     Plane *newplane;
2190     BPlane *cellPlane, *cellPlaneOrig;
2191     CellPropStruct cps;
2192 
2193     /* Unlike dbScaleCell(), this routine is only run on valid edit defs */
2194 
2195     cellDef->cd_flags |= CDBOXESCHANGED;
2196 
2197     /* Enumerate all unique cell uses, and move their position in the	*/
2198     /* bounding box and transform.					*/
2199 
2200     luhead = NULL;
2201 
2202     (void) DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
2203 
2204     cellPlane = BPNew();
2205     lu = luhead;
2206     while (lu != NULL)
2207     {
2208 	CellUse *use;
2209 	Rect *bbox;
2210 
2211 	use = lu->cellUse;
2212 	bbox = &use->cu_bbox;
2213 
2214 	/* TxPrintf("CellUse: BBox is ll (%d, %d), transform [%d %d %d %d %d %d]\n",
2215 		bbox->r_xbot, bbox->r_ybot,
2216 		use->cu_transform.t_a, use->cu_transform.t_b, use->cu_transform.t_c,
2217 		use->cu_transform.t_d, use->cu_transform.t_e, use->cu_transform.t_f); */
2218 
2219 	DBMovePoint(&bbox->r_ll, origx, origy);
2220 	DBMovePoint(&bbox->r_ur, origx, origy);
2221 
2222 	bbox = &use->cu_extended;
2223 	DBMovePoint(&bbox->r_ll, origx, origy);
2224 	DBMovePoint(&bbox->r_ur, origx, origy);
2225 
2226 	use->cu_transform.t_c -= origx;
2227 	use->cu_transform.t_f -= origy;
2228 
2229 	BPAdd(cellPlane, use);
2230 
2231 	lu = lu->cu_next;
2232     }
2233 
2234     /* Swap the CellDef's cell plane */
2235     cellPlaneOrig = cellDef->cd_cellPlane;
2236     cellDef->cd_cellPlane = cellPlane;
2237     BPFree(cellPlaneOrig);
2238 
2239     /* Free this linked cellUse structure */
2240     lu = luhead;
2241     while (lu != NULL)
2242     {
2243 	freeMagic((char *)lu);
2244 	lu = lu->cu_next;
2245     }
2246 
2247     /* Move all of the paint tiles in this cell by creating a new plane */
2248     /* and copying all tiles into the new plane at the new position.	 */
2249 
2250     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
2251     {
2252 	if (cellDef->cd_planes[pNum] == NULL) continue;
2253 	newplane = DBNewPlane((ClientData) TT_SPACE);
2254 	DBClearPaintPlane(newplane);
2255 	if (dbMovePlane(cellDef->cd_planes[pNum], newplane, pNum,
2256 		origx, origy, FALSE))
2257 	    cellDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
2258         DBFreePaintPlane(cellDef->cd_planes[pNum]);
2259 	TiFreePlane(cellDef->cd_planes[pNum]);
2260         cellDef->cd_planes[pNum] = newplane;
2261     }
2262 
2263     /* Also move the position of all labels. */
2264 
2265     if (cellDef->cd_labels)
2266     {
2267 	for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
2268 	{
2269 	    DBMovePoint(&lab->lab_rect.r_ll, origx, origy);
2270 	    DBMovePoint(&lab->lab_rect.r_ur, origx, origy);
2271 
2272 	    if (lab->lab_font >= 0)
2273 	    {
2274 		DBMovePoint(&lab->lab_bbox.r_ll, origx, origy);
2275 		DBMovePoint(&lab->lab_bbox.r_ur, origx, origy);
2276 	    }
2277 	}
2278     }
2279 
2280 donecell:
2281 
2282     /* The cellDef bounding box gets moved to match the new position. */
2283 
2284     DBMovePoint(&cellDef->cd_bbox.r_ll, origx, origy);
2285     DBMovePoint(&cellDef->cd_bbox.r_ur, origx, origy);
2286     DBMovePoint(&cellDef->cd_extended.r_ll, origx, origy);
2287     DBMovePoint(&cellDef->cd_extended.r_ur, origx, origy);
2288 
2289     /* Check all properties for ones with keys beginning with "MASKHINTS_"
2290      * or the key "FIXED_BBOX", and move them by the same amount as all
2291      * the geometry.
2292      */
2293 
2294     cps.cps_point.p_x = origx;
2295     cps.cps_point.p_y = origy;
2296     cps.cps_def = cellDef;
2297     DBPropEnum(cellDef, dbMoveProp, &cps);
2298     return 0;
2299 }
2300 
2301