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