1 /*
2 * DBcellcopy.c --
3 *
4 * Cell copying (yank and stuff)
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/DBcellcopy.c,v 1.13 2010/06/24 12:37:15 tim Exp $";
21 #endif /* not lint */
22
23 #include <stdio.h>
24 #include "utils/magic.h"
25 #include "utils/geometry.h"
26 #include "utils/geofast.h"
27 #include "utils/malloc.h"
28 #include "tiles/tile.h"
29 #include "utils/hash.h"
30 #include "utils/utils.h"
31 #include "database/database.h"
32 #include "database/databaseInt.h"
33 #include "textio/textio.h"
34 #include "windows/windows.h"
35 #include "dbwind/dbwind.h"
36 #include "commands/commands.h"
37
38 /*
39 * The following variable points to the tables currently used for
40 * painting. The paint tables are occasionally switched, by clients
41 * like the design-rule checker, by calling DBNewPaintTable. This
42 * paint table applies only to the routine in this module.
43 */
44 static PaintResultType (*dbCurPaintTbl)[NT][NT] = DBPaintResultTbl;
45
46 /*
47 * The following variable points to the version of DBPaintPlane used
48 * for painting during yanks. This is occasionally switched by clients
49 * such as the design-rule checker that need to use, for example,
50 * DBPaintPlaneMark instead of the standard version.
51 */
52 static int (*dbCurPaintPlane)() = DBPaintPlaneWrapper;
53
54 /* Structure passed to DBTreeSrTiles() */
55 struct copyAllArg
56 {
57 TileTypeBitMask *caa_mask; /* Mask of tile types to be copied */
58 Rect caa_rect; /* Clipping rect in target coords */
59 CellUse *caa_targetUse; /* Use to which tiles are copied */
60 void (*caa_func)(); /* Callback function for off-grid points */
61 Rect *caa_bbox; /* Bbox of material copied (in
62 * targetUse coords). Used only when
63 * copying cells.
64 */
65 };
66
67 /* Structure passed to DBSrPaintArea() */
68 struct copyArg
69 {
70 TileTypeBitMask *ca_mask; /* Mask of tile types to be copied */
71 Rect ca_rect; /* Clipping rect in source coords */
72 CellUse *ca_targetUse; /* Use to which tiles are copied */
73 Transform *ca_trans; /* Transform to target */
74 };
75
76 /* Structure passed to DBTreeSrLabels to hold information about
77 * copying labels.
78 */
79
80 struct copyLabelArg
81 {
82 CellUse *cla_targetUse; /* Use to which labels are copied. */
83 Rect *cla_bbox; /* If non-NULL, points to rectangle
84 * to be filled in with total area of
85 * all labels copied.
86 */
87 char *cla_glob; /* If non-NULL, used for glob-style
88 * matching of labels during copy.
89 */
90 };
91
92 /*
93 * ----------------------------------------------------------------------------
94 *
95 * DBPaintPlaneWrapper --
96 *
97 * Simple wrapper to DBPaintPlane.
98 * Note that this function is passed as a pointer on occasion, so
99 * it cannot be replaced with a macro!
100 *
101 * ----------------------------------------------------------------------------
102 */
103
104 int
DBPaintPlaneWrapper(def,pNum,type,area,undo)105 DBPaintPlaneWrapper(def, pNum, type, area, undo)
106 CellDef *def;
107 int pNum;
108 TileType type;
109 Rect *area;
110 PaintUndoInfo *undo;
111 {
112 TileType loctype = type & TT_LEFTMASK;
113 Rect expand;
114 int result;
115
116 undo->pu_pNum = pNum;
117 result = DBNMPaintPlane(def->cd_planes[pNum], type, area,
118 dbCurPaintTbl[pNum][loctype], undo);
119 GEO_EXPAND(area, 1, &expand);
120 DBMergeNMTiles(def->cd_planes[pNum], &expand, undo);
121 return result;
122 }
123
124 /*
125 * ----------------------------------------------------------------------------
126 *
127 * DBPaintPlaneMark --
128 *
129 * Another wrapper function to DBPaintPlane. This one is used for
130 * hierarchical DRC, and ensures that tiles are never painted twice
131 * on the same pass, so as not to cause false overlap errors.
132 *
133 * ----------------------------------------------------------------------------
134 */
135
136 int
DBPaintPlaneMark(def,pNum,type,area,undo)137 DBPaintPlaneMark(def, pNum, type, area, undo)
138 CellDef *def;
139 int pNum;
140 TileType type;
141 Rect *area;
142 PaintUndoInfo *undo;
143 {
144 TileType loctype = type & TT_LEFTMASK;
145
146 undo->pu_pNum = pNum;
147 return DBNMPaintPlane0(def->cd_planes[pNum], type, area,
148 dbCurPaintTbl[pNum][loctype], undo, (unsigned char)PAINT_MARK);
149 }
150
151 /*
152 * ----------------------------------------------------------------------------
153 *
154 * ----------------------------------------------------------------------------
155 */
156
157 int
DBPaintPlaneXor(def,pNum,type,area,undo)158 DBPaintPlaneXor(def, pNum, type, area, undo)
159 CellDef *def;
160 int pNum;
161 TileType type;
162 Rect *area;
163 PaintUndoInfo *undo;
164 {
165 TileType loctype = type & TT_LEFTMASK;
166
167 undo->pu_pNum = pNum;
168 return DBNMPaintPlane0(def->cd_planes[pNum], type, area,
169 dbCurPaintTbl[pNum][loctype], undo, (unsigned char)PAINT_XOR);
170 }
171
172 /*
173 * ----------------------------------------------------------------------------
174 *
175 * DBPaintPlaneActive ---
176 *
177 * This function calls DBPaintPlane, but first checks if the type
178 * being painted is an active layer. If the type is a contact,
179 * then the residues are checked to see if they are active layers.
180 * Painting proceeds accordingly.
181 *
182 * ----------------------------------------------------------------------------
183 */
184
185 int
DBPaintPlaneActive(def,pNum,type,area,undo)186 DBPaintPlaneActive(def, pNum, type, area, undo)
187 CellDef *def;
188 int pNum;
189 TileType type;
190 Rect *area;
191 PaintUndoInfo *undo;
192 {
193 TileType loctype = type & TT_LEFTMASK;
194 TileType t;
195
196 if (DBIsContact(loctype))
197 {
198 TileTypeBitMask tmask, *rMask;
199
200 rMask = DBResidueMask(loctype);
201 TTMaskAndMask3(&tmask, rMask, &DBActiveLayerBits);
202 if (!TTMaskEqual(&tmask, rMask))
203 {
204 if (!TTMaskIsZero(&tmask))
205 for (t = TT_TECHDEPBASE; t < DBNumUserLayers; t++)
206 if (TTMaskHasType(&tmask, t))
207 DBPaintPlaneWrapper(def, pNum, t | (type &
208 (TT_SIDE | TT_DIRECTION | TT_DIAGONAL)),
209 area, undo);
210 return 0;
211 }
212 }
213 if (TTMaskHasType(&DBActiveLayerBits, loctype))
214 return DBPaintPlaneWrapper(def, pNum, type, area, undo);
215 else
216 return 0;
217 }
218
219 /*
220 *-----------------------------------------------------------------------------
221 *
222 * DBCellCopyManhattanPaint --
223 *
224 * Copy paint from the tree rooted at scx->scx_use to the paint planes
225 * of targetUse, transforming according to the transform in scx.
226 * Only the types specified by typeMask are copied, and only Manhattan
227 * geometry is copied.
228 *
229 * Results:
230 * None.
231 *
232 * Side effects:
233 * Updates the paint planes in targetUse.
234 *
235 *-----------------------------------------------------------------------------
236 */
237
238 void
DBCellCopyManhattanPaint(scx,mask,xMask,targetUse)239 DBCellCopyManhattanPaint(scx, mask, xMask, targetUse)
240 SearchContext *scx; /* Describes root cell to search, area to
241 * copy, transform from root cell to coords
242 * of targetUse.
243 */
244 TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */
245 int xMask; /* Expansion state mask to be used in search */
246 CellUse *targetUse; /* Cell into which material is to be stuffed */
247 {
248 struct copyAllArg arg;
249 int dbCopyManhattanPaint();
250
251 arg.caa_mask = mask;
252 arg.caa_targetUse = targetUse;
253 arg.caa_func = NULL;
254 GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
255
256 (void) DBTreeSrTiles(scx, mask, xMask, dbCopyManhattanPaint, (ClientData) &arg);
257 }
258
259
260 /*
261 *-----------------------------------------------------------------------------
262 *
263 * DBCellCopyAllPaint --
264 *
265 * Copy paint from the tree rooted at scx->scx_use to the paint planes
266 * of targetUse, transforming according to the transform in scx.
267 * Only the types specified by typeMask are copied.
268 *
269 * Results:
270 * None.
271 *
272 * Side effects:
273 * Updates the paint planes in targetUse.
274 *
275 *-----------------------------------------------------------------------------
276 */
277
278 void
DBCellCopyAllPaint(scx,mask,xMask,targetUse)279 DBCellCopyAllPaint(scx, mask, xMask, targetUse)
280 SearchContext *scx; /* Describes root cell to search, area to
281 * copy, transform from root cell to coords
282 * of targetUse.
283 */
284 TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */
285 int xMask; /* Expansion state mask to be used in search */
286 CellUse *targetUse; /* Cell into which material is to be stuffed */
287 {
288 TileTypeBitMask locMask;
289 struct copyAllArg arg;
290 int dbCopyAllPaint();
291
292 arg.caa_mask = mask;
293 arg.caa_targetUse = targetUse;
294 arg.caa_func = NULL;
295 GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
296
297 /* Add any stacking types for the search (but not to mask passed as arg!) */
298 locMask = *mask;
299 DBMaskAddStacking(&locMask);
300
301 DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg);
302 }
303
304 /*
305 *-----------------------------------------------------------------------------
306 *
307 * DBCellCheckCopyAllPaint --
308 *
309 * Copy paint from the tree rooted at scx->scx_use to the paint planes
310 * of targetUse, transforming according to the transform in scx.
311 * Only the types specified by typeMask are copied.
312 *
313 * Results:
314 * None.
315 *
316 * Side effects:
317 * Updates the paint planes in targetUse.
318 *
319 *-----------------------------------------------------------------------------
320 */
321
322 void
DBCellCheckCopyAllPaint(scx,mask,xMask,targetUse,func)323 DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
324 SearchContext *scx; /* Describes root cell to search, area to
325 * copy, transform from root cell to coords
326 * of targetUse.
327 */
328 TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */
329 int xMask; /* Expansion state mask to be used in search */
330 CellUse *targetUse; /* Cell into which material is to be stuffed */
331 void (*func)(); /* Function to call on tile split error */
332 {
333 TileTypeBitMask locMask;
334 struct copyAllArg arg;
335 int dbCopyAllPaint();
336
337 arg.caa_mask = mask;
338 arg.caa_targetUse = targetUse;
339 arg.caa_func = func;
340 GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
341
342 /* Add any stacking types for the search (but not to mask passed as arg!) */
343 locMask = *mask;
344 DBMaskAddStacking(&locMask);
345
346 DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg);
347 }
348
349 /* Client data structure used by DBCellGenerateSubstrate() */
350
351 struct dbCopySubData {
352 Plane *csd_plane;
353 TileType csd_subtype;
354 int csd_pNum;
355 bool csd_modified;
356 };
357
358 /*
359 *-----------------------------------------------------------------------------
360 *
361 * DBCellGenerateSubstrate --
362 *
363 * This function is used by the extraction code in ExtSubtree.c.
364 * Paint substrate into the target use. Similar to DBCellCopyAllPaint(),
365 * but it finds space tiles on the substrate plane and converts them to
366 * a substrate type in the target, clipped to the cell boundary. This
367 * allows the extraction to find and record all substrate regions, both
368 * common (global substrate) and local (isolated substrate), without
369 * requiring a physical substrate type to be drawn into all cells.
370 *
371 * Unlike normal paint copying, this can only be done by painting the
372 * substrate type over the entire cell area and then erasing all areas
373 * belonging to not-substrate types in the source.
374 *
375 * Returns:
376 * Nothing.
377 *
378 * Side Effects:
379 * Paints into the targetUse's CellDef. This only happens if two
380 * conditions are met:
381 * (1) The techfile has defined "substrate"
382 * (2) The techfile defines a type corresponding to the substrate
383 *
384 * ----------------------------------------------------------------------------
385 */
386
387 Plane *
DBCellGenerateSubstrate(scx,subType,notSubMask,subShieldMask,targetDef)388 DBCellGenerateSubstrate(scx, subType, notSubMask, subShieldMask, targetDef)
389 SearchContext *scx;
390 TileType subType; /* Substrate paint type */
391 TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */
392 TileTypeBitMask *subShieldMask; /* Mask of types that shield substrate */
393 CellDef *targetDef;
394 {
395 struct dbCopySubData csd;
396 Plane *tempPlane;
397 int plane;
398 Rect rect;
399 int dbPaintSubFunc();
400 int dbEraseNonSub();
401 int dbCopySubFunc();
402
403 GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect);
404
405 /* Clip to bounding box of the top level cell */
406 GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox);
407
408 plane = DBPlane(subType);
409
410 tempPlane = DBNewPlane((ClientData) TT_SPACE);
411 DBClearPaintPlane(tempPlane);
412
413 csd.csd_subtype = subType;
414 csd.csd_plane = tempPlane;
415 csd.csd_pNum = plane;
416 csd.csd_modified = FALSE;
417
418 /* First paint the substrate type in the temporary plane over the */
419 /* area of all substrate shield types. */
420 /* Note: xMask is always zero, as this is only called from extract routines */
421 DBTreeSrTiles(scx, subShieldMask, 0, dbPaintSubFunc, (ClientData)&csd);
422 if (csd.csd_modified == FALSE) return NULL;
423
424 /* Now erase all areas that are non-substrate types in the source */
425 DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd);
426
427 /* Finally, copy the destination plane contents onto tempPlane */
428 DBSrPaintArea((Tile *)NULL, targetDef->cd_planes[plane], &TiPlaneRect,
429 &DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd);
430
431 return tempPlane;
432 }
433
434 /*
435 * Callback function for DBCellGenerateSubstrate()
436 * Finds tiles in the source def that belong to the list of types that
437 * shield the substrate (e.g., deep nwell), and paint the substrate type
438 * into the target plane over the same area.
439 */
440
441 int
dbPaintSubFunc(tile,cxp)442 dbPaintSubFunc(tile, cxp)
443 Tile *tile; /* Pointer to source tile with shield type */
444 TreeContext *cxp; /* Context from DBTreeSrTiles */
445 {
446 SearchContext *scx;
447 Rect sourceRect, targetRect;
448 int pNum;
449 TileType type, loctype, subType;
450 Plane *plane;
451 struct dbCopySubData *csd; /* Client data */
452
453 scx = cxp->tc_scx;
454 csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg;
455 plane = csd->csd_plane;
456 pNum = csd->csd_pNum;
457 subType = csd->csd_subtype;
458 type = TiGetTypeExact(tile);
459 if (IsSplit(tile))
460 {
461 loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
462 if (loctype == TT_SPACE) return 0;
463 }
464
465 /* Construct the rect for the tile */
466 TITORECT(tile, &sourceRect);
467
468 /* Transform to target coordinates */
469 GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
470
471 csd->csd_modified = TRUE;
472
473 return DBNMPaintPlane(plane, type, &targetRect, DBStdPaintTbl(subType, pNum),
474 (PaintUndoInfo *)NULL);
475 }
476
477 /*
478 * Callback function for DBCellGenerateSubstrate()
479 * Finds tiles on the substrate plane in the source def that are not the
480 * substrate type, and erases those areas from the target. This reduces
481 * the geometry in the target plane to areas that form isolated substrate
482 * regions. Regions belonging to the common global substrate are ignored.
483 */
484
485 int
dbEraseNonSub(tile,cxp)486 dbEraseNonSub(tile, cxp)
487 Tile *tile; /* Pointer to tile to erase from target */
488 TreeContext *cxp; /* Context from DBTreeSrTiles */
489 {
490 SearchContext *scx;
491 Rect sourceRect, targetRect;
492 Plane *plane; /* Plane of target data */
493 TileType type, loctype, subType;
494 struct dbCopySubData *csd;
495 int pNum;
496
497 csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg;
498 plane = csd->csd_plane;
499 subType = csd->csd_subtype;
500 pNum = csd->csd_pNum;
501
502 scx = cxp->tc_scx;
503
504 type = TiGetTypeExact(tile);
505 if (IsSplit(tile))
506 {
507 loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
508 if (loctype == TT_SPACE) return 0;
509 }
510
511 /* Construct the rect for the tile */
512 TITORECT(tile, &sourceRect);
513
514 /* Transform to target coordinates */
515 GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
516
517 /* Erase the substrate type from the area of this tile in the target plane. */
518 return DBNMPaintPlane(plane, type, &targetRect, DBStdEraseTbl(subType, pNum),
519 (PaintUndoInfo *)NULL);
520 }
521
522 /*
523 * Callback function for DBCellGenerateSubstrate()
524 * Simple paint function to copy all paint from the substrate plane of the
525 * source def into the target plane containing the isolated substrate
526 * regions.
527 */
528
529 int
dbCopySubFunc(tile,csd)530 dbCopySubFunc(tile, csd)
531 Tile *tile; /* Pointer to tile to erase from target */
532 struct dbCopySubData *csd; /* Client data */
533 {
534 Rect rect;
535 int pNum;
536 TileType type, loctype;
537 Plane *plane;
538
539 plane = csd->csd_plane;
540 pNum = csd->csd_pNum;
541 type = TiGetTypeExact(tile);
542 if (IsSplit(tile))
543 {
544 loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
545 if (loctype == TT_SPACE) return 0;
546 }
547 else
548 loctype = type;
549
550 /* Construct the rect for the tile */
551 TITORECT(tile, &rect);
552
553 return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(loctype, pNum),
554 (PaintUndoInfo *)NULL);
555 }
556
557 /*
558 *-----------------------------------------------------------------------------
559 *
560 * DBCellCopyAllLabels --
561 *
562 * Copy labels from the tree rooted at scx->scx_use to targetUse,
563 * transforming according to the transform in scx. Only labels
564 * attached to layers of the types specified by mask are copied.
565 * The area to be copied is determined by GEO_LABEL_IN_AREA.
566 *
567 * Results:
568 * None.
569 *
570 * Side effects:
571 * Copies labels to targetUse, clipping against scx->scx_area.
572 * If pArea is given, store in it the bounding box of all the
573 * labels copied.
574 *
575 *-----------------------------------------------------------------------------
576 */
577
578 void
DBCellCopyAllLabels(scx,mask,xMask,targetUse,pArea)579 DBCellCopyAllLabels(scx, mask, xMask, targetUse, pArea)
580 SearchContext *scx; /* Describes root cell to search, area to
581 * copy, transform from root cell to coords
582 * of targetUse.
583 */
584 TileTypeBitMask *mask; /* Only labels of these types are copied */
585 int xMask; /* Expansion state mask to be used in search */
586 CellUse *targetUse; /* Cell into which labels are to be stuffed */
587 Rect *pArea; /* If non-NULL, points to a box that will be
588 * filled in with bbox (in targetUse coords)
589 * of all labels copied. Will be degenerate
590 * if nothing was copied.
591 */
592 {
593 int dbCopyAllLabels();
594 struct copyLabelArg arg;
595
596 /* DBTeeSrLabels finds all the labels that we want plus some more.
597 * We'll filter out the ones that we don't need.
598 */
599
600 arg.cla_targetUse = targetUse;
601 arg.cla_bbox = pArea;
602 arg.cla_glob = NULL;
603 if (pArea != NULL)
604 {
605 pArea->r_xbot = 0;
606 pArea->r_xtop = -1;
607 }
608 (void) DBTreeSrLabels(scx, mask, xMask, (TerminalPath *) 0,
609 TF_LABEL_ATTACH, dbCopyAllLabels,
610 (ClientData) &arg);
611 }
612
613 /*ARGSUSED*/
614 int
dbCopyAllLabels(scx,lab,tpath,arg)615 dbCopyAllLabels(scx, lab, tpath, arg)
616 SearchContext *scx;
617 Label *lab;
618 TerminalPath *tpath;
619 struct copyLabelArg *arg;
620 {
621 Rect labTargetRect;
622 Point labOffset;
623 int targetPos, labRotate;
624 CellDef *def;
625
626 def = arg->cla_targetUse->cu_def;
627 if (arg->cla_glob != NULL)
628 if (!Match(arg->cla_glob, lab->lab_text))
629 return 0;
630 if (!GEO_LABEL_IN_AREA(&lab->lab_rect, &(scx->scx_area))) return 0;
631 GeoTransRect(&scx->scx_trans, &lab->lab_rect, &labTargetRect);
632 targetPos = GeoTransPos(&scx->scx_trans, lab->lab_just);
633 GeoTransPointDelta(&scx->scx_trans, &lab->lab_offset, &labOffset);
634 labRotate = GeoTransAngle(&scx->scx_trans, lab->lab_rotate);
635
636 /* Eliminate duplicate labels. Don't pay any attention to layers
637 * in deciding on duplicates: if text and position match, it's a
638 * duplicate.
639 */
640
641 DBEraseLabelsByContent(def, &labTargetRect, -1, lab->lab_text);
642 DBPutFontLabel(def, &labTargetRect, lab->lab_font,
643 lab->lab_size, labRotate, &labOffset, targetPos,
644 lab->lab_text, lab->lab_type, lab->lab_flags, lab->lab_port);
645 if (arg->cla_bbox != NULL)
646 {
647 GeoIncludeAll(&labTargetRect, arg->cla_bbox);
648
649 /* Rendered font labels include the bounding box of the text itself */
650 if (lab->lab_font >= 0)
651 {
652 GeoTransRect(&scx->scx_trans, &lab->lab_bbox, &labTargetRect);
653 GeoIncludeAll(&labTargetRect, arg->cla_bbox);
654 }
655 }
656 return 0;
657 }
658
659 /*
660 *-----------------------------------------------------------------------------
661 *
662 * DBCellCopyGlobLabels --
663 *
664 * Copy labels from the tree rooted at scx->scx_use to targetUse,
665 * transforming according to the transform in scx. Only labels
666 * attached to layers of the types specified by mask and which
667 * match the string "globmatch" by glob-style matching are copied.
668 * The area to be copied is determined by GEO_LABEL_IN_AREA.
669 *
670 * Results:
671 * None.
672 *
673 * Side effects:
674 * Copies labels to targetUse, clipping against scx->scx_area.
675 * If pArea is given, store in it the bounding box of all the
676 * labels copied.
677 *
678 *-----------------------------------------------------------------------------
679 */
680
681 void
DBCellCopyGlobLabels(scx,mask,xMask,targetUse,pArea,globmatch)682 DBCellCopyGlobLabels(scx, mask, xMask, targetUse, pArea, globmatch)
683 SearchContext *scx; /* Describes root cell to search, area to
684 * copy, transform from root cell to coords
685 * of targetUse.
686 */
687 TileTypeBitMask *mask; /* Only labels of these types are copied */
688 int xMask; /* Expansion state mask to be used in search */
689 CellUse *targetUse; /* Cell into which labels are to be stuffed */
690 Rect *pArea; /* If non-NULL, points to a box that will be
691 * filled in with bbox (in targetUse coords)
692 * of all labels copied. Will be degenerate
693 * if nothing was copied.
694 */
695 char *globmatch; /* If non-NULL, only labels matching this
696 * string by glob-style matching are copied.
697 */
698 {
699 int dbCopyAllLabels();
700 struct copyLabelArg arg;
701
702 /* DBTeeSrLabels finds all the labels that we want plus some more.
703 * We'll filter out the ones that we don't need.
704 */
705
706 arg.cla_targetUse = targetUse;
707 arg.cla_bbox = pArea;
708 arg.cla_glob = globmatch;
709 if (pArea != NULL)
710 {
711 pArea->r_xbot = 0;
712 pArea->r_xtop = -1;
713 }
714 (void) DBTreeSrLabels(scx, mask, xMask, (TerminalPath *) 0,
715 TF_LABEL_ATTACH, dbCopyAllLabels,
716 (ClientData) &arg);
717 }
718
719 /*
720 *-----------------------------------------------------------------------------
721 *
722 * DBCellCopyPaint --
723 *
724 * Copy paint from the paint planes of scx->scx_use to the paint planes
725 * of targetUse, transforming according to the transform in scx.
726 * Only the types specified by typeMask are copied.
727 *
728 * Results:
729 * None.
730 *
731 * Side effects:
732 * Updates the paint planes in targetUse.
733 *
734 *-----------------------------------------------------------------------------
735 */
736
737 void
DBCellCopyPaint(scx,mask,xMask,targetUse)738 DBCellCopyPaint(scx, mask, xMask, targetUse)
739 SearchContext *scx; /* Describes cell to search, area to
740 * copy, transform from cell to coords
741 * of targetUse.
742 */
743 TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */
744 int xMask; /* Expansion state mask to be used in search */
745 CellUse *targetUse; /* Cell into which material is to be stuffed */
746 {
747 int pNum;
748 PlaneMask planeMask;
749 TreeContext cxp;
750 TreeFilter filter;
751 struct copyAllArg arg;
752 int dbCopyAllPaint();
753
754 if (!DBDescendSubcell(scx->scx_use, xMask))
755 return;
756
757 arg.caa_mask = mask;
758 arg.caa_targetUse = targetUse;
759 arg.caa_func = NULL;
760 GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
761
762 /* Build dummy TreeContext */
763 cxp.tc_scx = scx;
764 cxp.tc_filter = &filter;
765 filter.tf_arg = (ClientData) &arg;
766
767 /* tf_func, tf_mask, tf_xmask, tf_planes, and tf_tpath are unneeded */
768
769 planeMask = DBTechTypesToPlanes(mask);
770 for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
771 if (PlaneMaskHasPlane(planeMask, pNum))
772 {
773 cxp.tc_plane = pNum;
774 (void) DBSrPaintArea((Tile *) NULL,
775 scx->scx_use->cu_def->cd_planes[pNum], &scx->scx_area,
776 mask, dbCopyAllPaint, (ClientData) &cxp);
777 }
778 }
779
780 /*
781 *-----------------------------------------------------------------------------
782 *
783 * DBCellCopyLabels --
784 *
785 * Copy labels from scx->scx_use to targetUse, transforming according to
786 * the transform in scx. Only labels attached to layers of the types
787 * specified by mask are copied. If mask contains the L_LABEL bit, then
788 * all labels are copied regardless of their layer. The area copied is
789 * determined by GEO_LABEL_IN_AREA.
790 *
791 * Results:
792 * None.
793 *
794 * Side effects:
795 * Updates the labels in targetUse. If pArea is given, it will
796 * be filled in with the bounding box of all labels copied.
797 *
798 *-----------------------------------------------------------------------------
799 */
800
801 void
DBCellCopyLabels(scx,mask,xMask,targetUse,pArea)802 DBCellCopyLabels(scx, mask, xMask, targetUse, pArea)
803 SearchContext *scx; /* Describes root cell to search, area to
804 * copy, transform from root cell to coords
805 * of targetUse.
806 */
807 TileTypeBitMask *mask; /* Only labels of these types are copied */
808 int xMask; /* Expansion state mask to be used in search */
809 CellUse *targetUse; /* Cell into which labels are to be stuffed */
810 Rect *pArea; /* If non-NULL, points to rectangle to be
811 * filled in with bbox (in targetUse coords)
812 * of all labels copied. Will be degenerate
813 * if no labels are copied.
814 */
815 {
816 Label *lab;
817 CellDef *def = targetUse->cu_def;
818 Rect labTargetRect;
819 Rect *rect = &scx->scx_area;
820 int targetPos, labRotate;
821 Point labOffset;
822 CellUse *sourceUse = scx->scx_use;
823
824 if (pArea != NULL)
825 {
826 pArea->r_xbot = 0;
827 pArea->r_xtop = -1;
828 }
829
830 if (!DBDescendSubcell(sourceUse, xMask))
831 return;
832
833 for (lab = sourceUse->cu_def->cd_labels; lab; lab = lab->lab_next)
834 if (GEO_LABEL_IN_AREA(&lab->lab_rect, rect) &&
835 (TTMaskHasType(mask, lab->lab_type)
836 || TTMaskHasType(mask, L_LABEL)))
837 {
838 GeoTransRect(&scx->scx_trans, &lab->lab_rect, &labTargetRect);
839 targetPos = GeoTransPos(&scx->scx_trans, lab->lab_just);
840 GeoTransPointDelta(&scx->scx_trans, &lab->lab_offset, &labOffset);
841 labRotate = GeoTransAngle(&scx->scx_trans, lab->lab_rotate);
842
843
844 /* Eliminate duplicate labels. Don't pay any attention to
845 * type when deciding on duplicates, since types can change
846 * later and then we'd have a duplicate.
847 */
848
849 DBEraseLabelsByContent(def, &labTargetRect, -1, lab->lab_text);
850 DBPutFontLabel(def, &labTargetRect, lab->lab_font,
851 lab->lab_size, labRotate, &labOffset, targetPos,
852 lab->lab_text, lab->lab_type, lab->lab_flags,
853 lab->lab_port);
854 if (pArea != NULL)
855 (void) GeoIncludeAll(&labTargetRect, pArea);
856 }
857 }
858
859 /***
860 *** Filter function for paint: Ignores diagonal (split) tiles for
861 *** purposes of selection searches.
862 ***/
863
864 int
dbCopyManhattanPaint(tile,cxp)865 dbCopyManhattanPaint(tile, cxp)
866 Tile *tile; /* Pointer to tile to copy */
867 TreeContext *cxp; /* Context from DBTreeSrTiles */
868 {
869 SearchContext *scx = cxp->tc_scx;
870 struct copyAllArg *arg;
871 Rect sourceRect, targetRect;
872 PaintUndoInfo ui;
873 CellDef *def;
874 TileType type;
875 int pNum = cxp->tc_plane;
876
877 /*
878 * Don't copy space tiles -- this copy is additive.
879 * We should never get passed a space tile, though, because
880 * the caller will be using DBSrPaintArea, so this is just
881 * a sanity check.
882 */
883
884 type = TiGetTypeExact(tile);
885 if (type == TT_SPACE || (type & TT_DIAGONAL))
886 return 0;
887
888 arg = (struct copyAllArg *) cxp->tc_filter->tf_arg;
889
890 /* Construct the rect for the tile in source coordinates */
891 TITORECT(tile, &sourceRect);
892
893 /* Transform to target coordinates */
894 GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
895
896 ui.pu_def = def = arg->caa_targetUse->cu_def;
897 def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
898
899 /* Clip against the target area */
900 GEOCLIP(&targetRect, &arg->caa_rect);
901
902 (*dbCurPaintPlane)(def, pNum, type, &targetRect, &ui);
903 return (0);
904 }
905
906
907 /***
908 *** Filter function for paint
909 ***/
910
911 int
dbCopyAllPaint(tile,cxp)912 dbCopyAllPaint(tile, cxp)
913 Tile *tile; /* Pointer to tile to copy */
914 TreeContext *cxp; /* Context from DBTreeSrTiles */
915 {
916 SearchContext *scx = cxp->tc_scx;
917 struct copyAllArg *arg;
918 Rect sourceRect, targetRect;
919 PaintUndoInfo ui;
920 CellDef *def;
921 TileType type = TiGetTypeExact(tile);
922 int pNum = cxp->tc_plane;
923 int result;
924 TileTypeBitMask *typeMask;
925
926 /*
927 * Don't copy space tiles -- this copy is additive.
928 * We should never get passed a space tile, though, because
929 * the caller will be using DBSrPaintArea, so this is just
930 * a sanity check.
931 */
932
933 bool splittile = FALSE;
934 TileType dinfo = 0;
935
936 if (IsSplit(tile))
937 {
938 splittile = TRUE;
939 dinfo = DBTransformDiagonal(type, &scx->scx_trans);
940 type = (SplitSide(tile)) ? SplitRightType(tile) :
941 SplitLeftType(tile);
942 }
943
944 if (type == TT_SPACE)
945 return 0;
946
947 arg = (struct copyAllArg *) cxp->tc_filter->tf_arg;
948 typeMask = arg->caa_mask;
949
950 /* Resolve what type we're going to paint, based on the type and mask */
951 if (!TTMaskHasType(typeMask, type))
952 {
953 TileTypeBitMask rMask, *tmask;
954
955 /* Simple case---typeMask has a residue of type on pNum */
956 tmask = DBResidueMask(type);
957 TTMaskAndMask3(&rMask, typeMask, tmask);
958 TTMaskAndMask(&rMask, &DBPlaneTypes[pNum]);
959 if (!TTMaskIsZero(&rMask))
960 {
961 for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++)
962 if (TTMaskHasType(&rMask, type))
963 break;
964 if (type == DBNumUserLayers) return 0; /* shouldn't happen */
965
966 /* Hopefully there's always just one type here---sanity check */
967 TTMaskClearType(&rMask, type);
968 if (!TTMaskIsZero(&rMask))
969 {
970 /* Diagnostic */
971 TxError("Bad assumption: Multiple types to paint! Fix me!\n");
972 }
973 }
974 else
975 {
976 type = DBPlaneToResidue(type, pNum);
977 if (!TTMaskHasType(typeMask, type)) return 0;
978 }
979 }
980
981 /* Construct the rect for the tile in source coordinates */
982 TITORECT(tile, &sourceRect);
983
984 /* Transform to target coordinates */
985 GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
986
987 ui.pu_def = def = arg->caa_targetUse->cu_def;
988
989 def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
990
991 /* Nonmanhattan geometry requires slightly different handling. */
992 /* Paint the whole tile and clip by erasing areas outside the */
993 /* clipping rectangle. */
994 if (splittile)
995 {
996 Point points[5];
997 Rect rrect, orect;
998 int np, i, j;
999
1000 GrClipTriangle(&targetRect, &arg->caa_rect, TRUE, dinfo, points, &np);
1001
1002 if (np == 0)
1003 return(0);
1004
1005 if (np >= 3)
1006 {
1007 for (i = 0; i < np; i++)
1008 {
1009 j = (i + 1) % np;
1010 if (points[i].p_x != points[j].p_x && points[i].p_y !=
1011 points[j].p_y)
1012 {
1013 /* Break out the triangle */
1014 rrect.r_xbot = points[i].p_x;
1015 rrect.r_xtop = points[j].p_x;
1016 rrect.r_ybot = points[i].p_y;
1017 rrect.r_ytop = points[j].p_y;
1018 GeoCanonicalRect(&rrect, &targetRect);
1019 break;
1020 }
1021 }
1022 if (i == np) /* Exactly one Manhattan rectangle */
1023 {
1024 rrect.r_xbot = points[0].p_x;
1025 rrect.r_xtop = points[2].p_x;
1026 rrect.r_ybot = points[0].p_y;
1027 rrect.r_ytop = points[2].p_y;
1028 GeoCanonicalRect(&rrect, &targetRect);
1029 dinfo = 0;
1030 }
1031 else if (np >= 4) /* Process extra rectangles in the area */
1032 {
1033 /* "orect" is the bounding box of the polygon returned */
1034 /* by ClipTriangle. */
1035
1036 orect.r_xtop = orect.r_xbot = points[0].p_x;
1037 orect.r_ytop = orect.r_ybot = points[0].p_y;
1038 for (i = 0; i < np; i++)
1039 GeoIncludePoint(&points[i], &orect);
1040
1041 /* Rectangle to left or right */
1042 rrect.r_ybot = orect.r_ybot;
1043 rrect.r_ytop = orect.r_ytop;
1044 if (targetRect.r_xbot > orect.r_xbot)
1045 {
1046 rrect.r_xbot = orect.r_xbot;
1047 rrect.r_xtop = targetRect.r_xbot;
1048 }
1049 else if (targetRect.r_xtop < orect.r_xtop)
1050 {
1051 rrect.r_xtop = orect.r_xtop;
1052 rrect.r_xbot = targetRect.r_xtop;
1053 }
1054 else
1055 goto topbottom;
1056
1057 (*dbCurPaintPlane)(def, pNum, type, &rrect, &ui);
1058
1059 topbottom:
1060 /* Rectangle to top or bottom */
1061 rrect.r_xbot = targetRect.r_xbot;
1062 rrect.r_xtop = targetRect.r_xtop;
1063 if (targetRect.r_ybot > orect.r_ybot)
1064 {
1065 rrect.r_ybot = orect.r_ybot;
1066 rrect.r_ytop = targetRect.r_ybot;
1067 }
1068 else if (targetRect.r_ytop < orect.r_ytop)
1069 {
1070 rrect.r_ytop = orect.r_ytop;
1071 rrect.r_ybot = targetRect.r_ytop;
1072 }
1073 else
1074 goto splitdone;
1075
1076 (*dbCurPaintPlane)(def, pNum, type, &rrect, &ui);
1077 }
1078 }
1079 }
1080 else
1081 /* Clip against the target area */
1082 GEOCLIP(&targetRect, &arg->caa_rect);
1083
1084 splitdone:
1085
1086 result = (*dbCurPaintPlane)(def, pNum, dinfo | type, &targetRect, &ui);
1087 if ((result != 0) && (arg->caa_func != NULL))
1088 {
1089 /* result == 1 used exclusively for DRC off-grid error flagging */
1090 DRCOffGridError(&targetRect);
1091 }
1092
1093 return (0);
1094 }
1095
1096 /*
1097 *-----------------------------------------------------------------------------
1098 *
1099 * DBCellCopyAllCells --
1100 *
1101 * Copy unexpanded subcells from the tree rooted at scx->scx_use
1102 * to the subcell plane of targetUse, transforming according to
1103 * the transform in scx.
1104 *
1105 * This effectively "flattens" a cell hierarchy in the sense that
1106 * all unexpanded subcells in a region (which would appear in the
1107 * display as bounding boxes) are copied into targetUse without
1108 * regard for their original location in the hierarchy of scx->scx_use.
1109 * If an array is unexpanded, it is copied as an array, not as a
1110 * collection of individual cells.
1111 *
1112 * Results:
1113 * None.
1114 *
1115 * Side effects:
1116 * Updates the cell plane in targetUse. If pArea is given, it
1117 * will be filled in with the total area of all cells copied.
1118 *
1119 *-----------------------------------------------------------------------------
1120 */
1121
1122 void
DBCellCopyAllCells(scx,xMask,targetUse,pArea)1123 DBCellCopyAllCells(scx, xMask, targetUse, pArea)
1124 SearchContext *scx; /* Describes root cell to search, area to
1125 * copy, transform from root cell to coords
1126 * of targetUse.
1127 */
1128 CellUse *targetUse; /* Cell into which material is to be stuffed */
1129 int xMask; /* Expansion state mask to be used in
1130 * searching. Cells not expanded according
1131 * to this mask are copied. To copy everything
1132 * in the subtree under scx->scx_use without
1133 * regard to expansion, pass a mask of 0.
1134 */
1135 Rect *pArea; /* If non-NULL, points to a rectangle to be
1136 * filled in with bbox (in targetUse coords)
1137 * of all cells copied. Will be degenerate
1138 * if nothing was copied.
1139 */
1140 {
1141 struct copyAllArg arg;
1142 int dbCellCopyCellsFunc();
1143
1144 arg.caa_targetUse = targetUse;
1145 arg.caa_bbox = pArea;
1146 if (pArea != NULL)
1147 {
1148 pArea->r_xbot = 0; /* Make bounding box empty initially. */
1149 pArea->r_xtop = -1;
1150 }
1151 GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
1152
1153 (void) DBTreeSrCells(scx, xMask, dbCellCopyCellsFunc, (ClientData) &arg);
1154 }
1155
1156 /*
1157 *-----------------------------------------------------------------------------
1158 *
1159 * DBCellCopyCells --
1160 *
1161 * Copy all subcells that are immediate children of scx->scx_use->cu_def
1162 * into the subcell plane of targetUse, transforming according to
1163 * the transform in scx. Arrays are copied as arrays, not as a
1164 * collection of individual cells. If a cell is already present in
1165 * targetUse that would be exactly duplicated by a new cell, the new
1166 * cell isn't copied.
1167 *
1168 * Results:
1169 * None.
1170 *
1171 * Side effects:
1172 * Updates the cell plane in targetUse. If pArea is given, it will
1173 * be filled in with the bounding box of all cells copied.
1174 *
1175 *-----------------------------------------------------------------------------
1176 */
1177
1178 void
DBCellCopyCells(scx,targetUse,pArea)1179 DBCellCopyCells(scx, targetUse, pArea)
1180 SearchContext *scx; /* Describes root cell to search, area to
1181 * copy, transform from coords of
1182 * scx->scx_use->cu_def to coords of targetUse.
1183 */
1184 CellUse *targetUse; /* Cell into which material is to be stuffed */
1185 Rect *pArea; /* If non-NULL, points to rectangle to be
1186 * filled in with bbox (in targetUse coords)
1187 * of all cells copied. Will be degenerate
1188 * if nothing was copied.
1189 */
1190 {
1191 struct copyAllArg arg;
1192 int dbCellCopyCellsFunc();
1193
1194 arg.caa_targetUse = targetUse;
1195 arg.caa_bbox = pArea;
1196 if (pArea != NULL)
1197 {
1198 pArea->r_xbot = 0;
1199 pArea->r_xtop = -1;
1200 }
1201 GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
1202
1203 (void) DBCellSrArea(scx, dbCellCopyCellsFunc, (ClientData) &arg);
1204 }
1205
1206 /*
1207 *-----------------------------------------------------------------------------
1208 *
1209 * dbCellCopyCellsFunc --
1210 *
1211 * Do the actual work of yanking cells for DBCellCopyAllCells() and
1212 * DBCellCopyCells() above.
1213 *
1214 * Results:
1215 * Always return 2.
1216 *
1217 * Side effects:
1218 * Updates the cell plane in arg->caa_targetUse->cu_def.
1219 *
1220 *-----------------------------------------------------------------------------
1221 */
1222
1223 int
dbCellCopyCellsFunc(scx,arg)1224 dbCellCopyCellsFunc(scx, arg)
1225 SearchContext *scx; /* Pointer to search context containing
1226 * ptr to cell use to be copied,
1227 * and transform to the target def.
1228 */
1229 struct copyAllArg *arg; /* Client data from caller */
1230 {
1231 CellUse *use, *newUse;
1232 CellDef *def;
1233 int xsep, ysep, xbase, ybase;
1234 Transform newTrans;
1235
1236 use = scx->scx_use;
1237 def = use->cu_def;
1238
1239 /* Don't allow circular structures! */
1240
1241 if (DBIsAncestor(def, arg->caa_targetUse->cu_def))
1242 {
1243 TxPrintf("Copying %s would create a circularity in the",
1244 def->cd_name);
1245 TxPrintf(" cell hierarchy \n(%s is already its ancestor)",
1246 arg->caa_targetUse->cu_def->cd_name);
1247 TxPrintf(" so cell not copied.\n");
1248 return 2;
1249 }
1250
1251 /* When creating a new use, try to re-use the id from the old
1252 * one. Only create a new one if the old id can't be used.
1253 */
1254
1255 newUse = DBCellNewUse(def, (char *) use->cu_id);
1256 if (!DBLinkCell(newUse, arg->caa_targetUse->cu_def))
1257 {
1258 freeMagic((char *) newUse->cu_id);
1259 newUse->cu_id = NULL;
1260 (void) DBLinkCell(newUse, arg->caa_targetUse->cu_def);
1261 }
1262 newUse->cu_expandMask = use->cu_expandMask;
1263 newUse->cu_flags = use->cu_flags;
1264
1265 /* The translation stuff is funny, since we got one element of
1266 * the array, but not necessarily the lower-left element. To
1267 * get the transform for the array as a whole, subtract off fo
1268 * the index of the element. The easiest way to see how this
1269 * works is to look at the code in dbCellSrFunc; the stuff here
1270 * is the opposite.
1271 */
1272
1273 if (use->cu_xlo > use->cu_xhi) xsep = -use->cu_xsep;
1274 else xsep = use->cu_xsep;
1275 if (use->cu_ylo > use->cu_yhi) ysep = -use->cu_ysep;
1276 else ysep = use->cu_ysep;
1277 xbase = xsep * (scx->scx_x - use->cu_xlo);
1278 ybase = ysep * (scx->scx_y - use->cu_ylo);
1279 GeoTransTranslate(-xbase, -ybase, &scx->scx_trans, &newTrans);
1280 DBSetArray(use, newUse);
1281 DBSetTrans(newUse, &newTrans);
1282 if (DBCellFindDup(newUse, arg->caa_targetUse->cu_def) != NULL)
1283 {
1284 if (!(arg->caa_targetUse->cu_def->cd_flags & CDINTERNAL))
1285 {
1286 TxError("Cell \"%s\" would end up on top of an identical copy\n",
1287 newUse->cu_id);
1288 TxError(" of itself. I'm going to forget about the");
1289 TxError(" new copy.\n");
1290 }
1291 DBUnLinkCell(newUse, arg->caa_targetUse->cu_def);
1292 (void) DBCellDeleteUse(newUse);
1293 }
1294 else
1295 {
1296 DBPlaceCell(newUse, arg->caa_targetUse->cu_def);
1297 if (arg->caa_bbox != NULL)
1298 (void) GeoIncludeAll(&newUse->cu_bbox, arg->caa_bbox);
1299 }
1300 return 2;
1301 }
1302
1303 /*
1304 * ----------------------------------------------------------------------------
1305 *
1306 * DBNewPaintTable --
1307 *
1308 * This procedure changes the paint table to be used by the
1309 * DBCellCopyPaint and DBCellCopyAllPaint procedures.
1310 *
1311 * Results:
1312 * The return value is the address of the paint table that used
1313 * to be in effect. It is up to the client to restore this
1314 * value with another call to this procedure.
1315 *
1316 * Side effects:
1317 * A new paint table takes effect. However, if newTable is NULL,
1318 * then the old paint table remains active. This allows one to
1319 * get a pointer to the active paint table without altering it.
1320 *
1321 * ----------------------------------------------------------------------------
1322 */
1323
1324 PaintResultType (*
1325 DBNewPaintTable(newTable))[NT][NT]
1326 PaintResultType (*newTable)[NT][NT]; /* Address of new paint table. */
1327 {
1328 PaintResultType (*oldTable)[NT][NT] = dbCurPaintTbl;
1329 if (newTable) dbCurPaintTbl = newTable;
1330 return oldTable;
1331 }
1332
1333 /*
1334 * ----------------------------------------------------------------------------
1335 *
1336 * DBNewPaintPlane --
1337 *
1338 * This procedure changes the painting procedure to be used by the
1339 * DBCellCopyPaint and DBCellCopyAllPaint procedures.
1340 *
1341 * Results:
1342 * The return value is the address of the paint procedure that
1343 * used to be in effect. It is up to the client to restore this
1344 * value with another call to this procedure.
1345 *
1346 * Side effects:
1347 * A new paint procedure takes effect.
1348 *
1349 * ----------------------------------------------------------------------------
1350 */
1351
1352 IntProc
1353 DBNewPaintPlane(newProc)
1354 int (*newProc)(); /* Address of new procedure */
1355 {
1356 int (*oldProc)() = dbCurPaintPlane;
1357 dbCurPaintPlane = newProc;
1358 return (oldProc);
1359 }
1360