/* * DBcellcopy.c -- * * Cell copying (yank and stuff) * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint 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 $"; #endif /* not lint */ #include #include /* For strlen() and strncmp() */ #include /* for isspace() */ #include "utils/magic.h" #include "utils/geometry.h" #include "utils/geofast.h" #include "utils/malloc.h" #include "tiles/tile.h" #include "utils/hash.h" #include "utils/utils.h" #include "database/database.h" #include "database/databaseInt.h" #include "textio/textio.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "commands/commands.h" /* C99 compat */ #include "graphics/graphics.h" /* * The following variable points to the tables currently used for * painting. The paint tables are occasionally switched, by clients * like the design-rule checker, by calling DBNewPaintTable. This * paint table applies only to the routine in this module. */ static PaintResultType (*dbCurPaintTbl)[NT][NT] = DBPaintResultTbl; /* * The following variable points to the version of DBPaintPlane used * for painting during yanks. This is occasionally switched by clients * such as the design-rule checker that need to use, for example, * DBPaintPlaneMark instead of the standard version. */ static int (*dbCurPaintPlane)() = DBPaintPlaneWrapper; /* Structure passed to DBTreeSrTiles() */ struct copyAllArg { TileTypeBitMask *caa_mask; /* Mask of tile types to be copied */ Rect caa_rect; /* Clipping rect in target coords */ CellUse *caa_targetUse; /* Use to which tiles are copied */ void (*caa_func)(); /* Callback function for off-grid points */ Rect *caa_bbox; /* Bbox of material copied (in * targetUse coords). Used only when * copying cells. */ }; /* Structure passed to DBSrPaintArea() */ struct copyArg { TileTypeBitMask *ca_mask; /* Mask of tile types to be copied */ Rect ca_rect; /* Clipping rect in source coords */ CellUse *ca_targetUse; /* Use to which tiles are copied */ Transform *ca_trans; /* Transform to target */ }; /* Structure passed to DBTreeSrLabels to hold information about * copying labels. */ struct copyLabelArg { CellUse *cla_targetUse; /* Use to which labels are copied. */ Rect *cla_bbox; /* If non-NULL, points to rectangle * to be filled in with total area of * all labels copied. */ char *cla_glob; /* If non-NULL, used for glob-style * matching of labels during copy. */ }; /* * ---------------------------------------------------------------------------- * * DBPaintPlaneWrapper -- * * Simple wrapper to DBPaintPlane. * Note that this function is passed as a pointer on occasion, so * it cannot be replaced with a macro! * * ---------------------------------------------------------------------------- */ int DBPaintPlaneWrapper(def, pNum, type, area, undo) CellDef *def; int pNum; TileType type; Rect *area; PaintUndoInfo *undo; { TileType loctype = type & TT_LEFTMASK; Rect expand; int result; undo->pu_pNum = pNum; result = DBNMPaintPlane(def->cd_planes[pNum], type, area, dbCurPaintTbl[pNum][loctype], undo); GEO_EXPAND(area, 1, &expand); DBMergeNMTiles(def->cd_planes[pNum], &expand, undo); return result; } /* * ---------------------------------------------------------------------------- * * DBPaintPlaneMark -- * * Another wrapper function to DBPaintPlane. This one is used for * hierarchical DRC, and ensures that tiles are never painted twice * on the same pass, so as not to cause false overlap errors. * * ---------------------------------------------------------------------------- */ int DBPaintPlaneMark(def, pNum, type, area, undo) CellDef *def; int pNum; TileType type; Rect *area; PaintUndoInfo *undo; { TileType loctype = type & TT_LEFTMASK; undo->pu_pNum = pNum; return DBNMPaintPlane0(def->cd_planes[pNum], type, area, dbCurPaintTbl[pNum][loctype], undo, (unsigned char)PAINT_MARK); } /* * ---------------------------------------------------------------------------- * * ---------------------------------------------------------------------------- */ int DBPaintPlaneXor(def, pNum, type, area, undo) CellDef *def; int pNum; TileType type; Rect *area; PaintUndoInfo *undo; { TileType loctype = type & TT_LEFTMASK; undo->pu_pNum = pNum; return DBNMPaintPlane0(def->cd_planes[pNum], type, area, dbCurPaintTbl[pNum][loctype], undo, (unsigned char)PAINT_XOR); } /* * ---------------------------------------------------------------------------- * * DBPaintPlaneActive --- * * This function calls DBPaintPlane, but first checks if the type * being painted is an active layer. If the type is a contact, * then the residues are checked to see if they are active layers. * Painting proceeds accordingly. * * ---------------------------------------------------------------------------- */ int DBPaintPlaneActive(def, pNum, type, area, undo) CellDef *def; int pNum; TileType type; Rect *area; PaintUndoInfo *undo; { TileType loctype = type & TT_LEFTMASK; TileType t; if (DBIsContact(loctype)) { TileTypeBitMask tmask, *rMask; rMask = DBResidueMask(loctype); TTMaskAndMask3(&tmask, rMask, &DBActiveLayerBits); if (!TTMaskEqual(&tmask, rMask)) { if (!TTMaskIsZero(&tmask)) for (t = TT_TECHDEPBASE; t < DBNumUserLayers; t++) if (TTMaskHasType(&tmask, t)) DBPaintPlaneWrapper(def, pNum, t | (type & (TT_SIDE | TT_DIRECTION | TT_DIAGONAL)), area, undo); return 0; } } if (TTMaskHasType(&DBActiveLayerBits, loctype)) return DBPaintPlaneWrapper(def, pNum, type, area, undo); else return 0; } /* *----------------------------------------------------------------------------- * * DBCellCopyManhattanPaint -- * * Copy paint from the tree rooted at scx->scx_use to the paint planes * of targetUse, transforming according to the transform in scx. * Only the types specified by typeMask are copied, and only Manhattan * geometry is copied. * * Results: * None. * * Side effects: * Updates the paint planes in targetUse. * *----------------------------------------------------------------------------- */ void DBCellCopyManhattanPaint(scx, mask, xMask, targetUse) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which material is to be stuffed */ { struct copyAllArg arg; int dbCopyManhattanPaint(); arg.caa_mask = mask; arg.caa_targetUse = targetUse; arg.caa_func = NULL; GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); (void) DBTreeSrTiles(scx, mask, xMask, dbCopyManhattanPaint, (ClientData) &arg); } /* *----------------------------------------------------------------------------- * * DBCellCopyAllPaint -- * * Copy paint from the tree rooted at scx->scx_use to the paint planes * of targetUse, transforming according to the transform in scx. * Only the types specified by typeMask are copied. * * Results: * None. * * Side effects: * Updates the paint planes in targetUse. * *----------------------------------------------------------------------------- */ void DBCellCopyAllPaint(scx, mask, xMask, targetUse) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which material is to be stuffed */ { TileTypeBitMask locMask; struct copyAllArg arg; int dbCopyAllPaint(); arg.caa_mask = mask; arg.caa_targetUse = targetUse; arg.caa_func = NULL; GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); /* Add any stacking types for the search (but not to mask passed as arg!) */ locMask = *mask; DBMaskAddStacking(&locMask); DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg); } /* *----------------------------------------------------------------------------- * * DBCellCheckCopyAllPaint -- * * Copy paint from the tree rooted at scx->scx_use to the paint planes * of targetUse, transforming according to the transform in scx. * Only the types specified by typeMask are copied. * * Results: * None. * * Side effects: * Updates the paint planes in targetUse. * *----------------------------------------------------------------------------- */ void DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which material is to be stuffed */ void (*func)(); /* Function to call on tile split error */ { TileTypeBitMask locMask; struct copyAllArg arg; int dbCopyAllPaint(); arg.caa_mask = mask; arg.caa_targetUse = targetUse; arg.caa_func = func; GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); /* Add any stacking types for the search (but not to mask passed as arg!) */ locMask = *mask; DBMaskAddStacking(&locMask); DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg); } /* Data structure used by dbCopyMaskHintsFunc */ struct propUseDefStruct { CellDef *puds_source; CellDef *puds_dest; Transform *puds_trans; /* Transform from source use to dest */ }; /* *----------------------------------------------------------------------------- * * dbCopyMaskHintsFunc -- * * Callback function used by DBCellCopyMaskHints(). Does the work * of copying a "mask-hints" property from a child instance into its * parent def, modifying coordinates according to the child instance's * transform. * * Results: * 0 to keep the search going. * * Side effects: * Creates properties in the parent cell. * *----------------------------------------------------------------------------- */ int dbCopyMaskHintsFunc(key, value, puds) char *key; ClientData value; struct propUseDefStruct *puds; { CellDef *dest = puds->puds_dest; Transform *trans = puds->puds_trans; char *propstr = (char *)value; char *parentprop, *newvalue, *vptr; Rect r, rnew; bool propfound; if (!strncmp(key, "MASKHINTS_", 10)) { char *vptr, *lastval; int lastlen; /* Append to existing mask hint (if any) */ parentprop = (char *)DBPropGet(dest, key, &propfound); newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL; vptr = propstr; while (*vptr != '\0') { if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot, &r.r_xtop, &r.r_ytop) == 4) { GeoTransRect(trans, &r, &rnew); lastval = newvalue; lastlen = (lastval) ? strlen(lastval) : 0; newvalue = mallocMagic(40 + lastlen); if (lastval) strcpy(newvalue, lastval); else *newvalue = '\0'; sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "", rnew.r_xbot, rnew.r_ybot, rnew.r_xtop, rnew.r_ytop); if (lastval) freeMagic(lastval); while (*vptr && !isspace(*vptr)) vptr++; while (*vptr && isspace(*vptr)) vptr++; while (*vptr && !isspace(*vptr)) vptr++; while (*vptr && isspace(*vptr)) vptr++; while (*vptr && !isspace(*vptr)) vptr++; while (*vptr && isspace(*vptr)) vptr++; while (*vptr && !isspace(*vptr)) vptr++; while (*vptr && isspace(*vptr)) vptr++; } else break; } if (newvalue) DBPropPut(dest, key, newvalue); } return 0; } /* *----------------------------------------------------------------------------- * * DBCellCopyMaskHints -- * * This function is used by the "flatten -inplace" command option to * transfer information from mask-hint properties from a flattened * child cell to the parent. * * Results: * None. * * Side effects: * Properties copied from child to parent cell and modified. * *----------------------------------------------------------------------------- */ void DBCellCopyMaskHints(child, parent, transform) CellUse *child; CellDef *parent; Transform *transform; { struct propUseDefStruct puds; puds.puds_source = child->cu_def; puds.puds_dest = parent; puds.puds_trans = transform; DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds); } /* *----------------------------------------------------------------------------- * * dbFlatCopyMaskHintsFunc --- * * Callback function used by DBFlatCopyMaskHints() to copy mask hint * properties from a child cell into a flattened cell def. This is * simply a variant of DBCellCopyMaskHints() above, with arguments * appropriate to being called from DBTreeSrCells(), and applying * the transform from the search context. * * Results: * 0 to keep the cell search going. * * Side effects: * Generates properties in the target def. * *----------------------------------------------------------------------------- */ int dbFlatCopyMaskHintsFunc(scx, def) SearchContext *scx; CellDef *def; { struct propUseDefStruct puds; CellUse *use = scx->scx_use; puds.puds_source = scx->scx_use->cu_def; puds.puds_dest = def; puds.puds_trans = &scx->scx_trans; DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds); return 0; } /* *----------------------------------------------------------------------------- * * DBFlatCopyMaskHints -- * * This function is used by the "flatten" command option to copy information * in mask-hint properties from flattened children to a flattened cell def. * * Results: * None. * * Side effects: * Properties copied from child to parent cell and modified. * *----------------------------------------------------------------------------- */ void DBFlatCopyMaskHints(scx, xMask, targetUse) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which properties will be added */ { DBTreeSrCells(scx, xMask, dbFlatCopyMaskHintsFunc, (ClientData)targetUse->cu_def); } /* *----------------------------------------------------------------------------- * * DBFlattenInPlace -- * * This function is used by the "flatten" command "-doinplace" option to * flatten a cell instance into its parent cell. * * Results: * None. * * Side effects: * Indicated cell use is flattened into the edit cell def. * *----------------------------------------------------------------------------- */ void DBFlattenInPlace(use, dest, xMask, dolabels, toplabels, doclear) CellUse *use; /* Cell use to flatten */ CellUse *dest; /* Cell use to flatten into */ int xMask; /* Search mask for flattening */ bool dolabels; /* Option to flatten labels */ bool toplabels; /* Option to selectively flatten top-level labels */ bool doclear; /* Delete the original use if TRUE */ { Label *lab; SearchContext scx; int xsep, ysep, xbase, ybase; if (dest == NULL) { TxError("The target cell does not exist or is not editable.\n"); return; } scx.scx_use = use; scx.scx_area = use->cu_def->cd_bbox; /* Mark labels in the subcell top level for later handling */ for (lab = scx.scx_use->cu_def->cd_labels; lab; lab = lab->lab_next) lab->lab_flags |= LABEL_GENERATE; scx.scx_x = use->cu_xlo; scx.scx_y = use->cu_ylo; while (TRUE) { if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi)) scx.scx_trans = use->cu_transform; else { if (use->cu_xlo > use->cu_xhi) xsep = -use->cu_xsep; else xsep = use->cu_xsep; if (use->cu_ylo > use->cu_yhi) ysep = -use->cu_ysep; else ysep = use->cu_ysep; xbase = xsep * (scx.scx_x - use->cu_xlo); ybase = ysep * (scx.scx_y - use->cu_ylo); GeoTransTranslate(xbase, ybase, &use->cu_transform, &scx.scx_trans); } DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, xMask, dest); if (dolabels) FlatCopyAllLabels(&scx, &DBAllTypeBits, xMask, dest); else if (toplabels) { int savemask = scx.scx_use->cu_expandMask; scx.scx_use->cu_expandMask = CU_DESCEND_SPECIAL; DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_SPECIAL, dest, NULL); scx.scx_use->cu_expandMask = savemask; } if (xMask != CU_DESCEND_ALL) DBCellCopyAllCells(&scx, xMask, dest, (Rect *)NULL); /* Marked labels coming from the subcell top level must not be */ /* ports, and text should be prefixed with the subcell name. */ for (lab = dest->cu_def->cd_labels; lab; lab = lab->lab_next) { Label *newlab; char *newtext; if (lab->lab_flags & LABEL_GENERATE) { newtext = mallocMagic(strlen(lab->lab_text) + strlen(scx.scx_use->cu_id) + 2); if ((use->cu_xlo != use->cu_xhi) && (use->cu_ylo != use->cu_yhi)) sprintf(newtext, "%s[%d][%d]/%s", scx.scx_use->cu_id, scx.scx_x, scx.scx_y, lab->lab_text); else if (use->cu_xlo != use->cu_xhi) sprintf(newtext, "%s[%d]/%s", scx.scx_use->cu_id, scx.scx_x, lab->lab_text); else if (use->cu_ylo != use->cu_yhi) sprintf(newtext, "%s[%d]/%s", scx.scx_use->cu_id, scx.scx_y, lab->lab_text); else sprintf(newtext, "%s/%s", scx.scx_use->cu_id, lab->lab_text); DBPutFontLabel(dest->cu_def, &lab->lab_rect, lab->lab_font, lab->lab_size, lab->lab_rotate, &lab->lab_offset, lab->lab_just, newtext, lab->lab_type, 0, 0); DBEraseLabelsByContent(dest->cu_def, &lab->lab_rect, -1, lab->lab_text); freeMagic(newtext); } } /* Copy and transform mask hints from child to parent */ DBCellCopyMaskHints(scx.scx_use, dest->cu_def, &scx.scx_trans); /* Stop processing if the use is not arrayed. */ if ((scx.scx_x == use->cu_xhi) && (scx.scx_y == use->cu_yhi)) break; if (use->cu_xlo < use->cu_xhi) scx.scx_x++; else if (use->cu_xlo > use->cu_xhi) scx.scx_x--; if (((use->cu_xlo < use->cu_xhi) && (scx.scx_x > use->cu_xhi)) || ((use->cu_xlo > use->cu_xhi) && (scx.scx_x < use->cu_xhi))) { if (use->cu_ylo < use->cu_yhi) { scx.scx_y++; scx.scx_x = use->cu_xlo; } else if (use->cu_ylo > use->cu_yhi) { scx.scx_y--; scx.scx_x = use->cu_xlo; } } } /* Unmark labels in the subcell top level */ for (lab = scx.scx_use->cu_def->cd_labels; lab; lab = lab->lab_next) lab->lab_flags &= ~LABEL_GENERATE; /* Remove the use from the parent def */ if (doclear) DBDeleteCell(scx.scx_use); /* Was: &scx.scx_use->cu_def->cd_bbox */ DBWAreaChanged(dest->cu_def, &scx.scx_use->cu_bbox, DBW_ALLWINDOWS, &DBAllButSpaceAndDRCBits); } /* Client data structure used by DBCellFlattenAllCells() */ struct dbFlattenAllData { CellUse *fad_dest; /* Cell use to flatten into */ int fad_xmask; /* Search mask for flattening */ bool fad_dolabels; /* Option to flatten labels */ bool fad_toplabels; /* Option to selectively flatten top-level labels */ }; /* *----------------------------------------------------------------------------- * * dbCellFlattenCellsFunc -- * * Do the actual work of flattening cells for DBCellFlattenAllCells(). * * Results: * Always return 2. * * Side effects: * Updates the paint planes of EditRootDef. * *----------------------------------------------------------------------------- */ int dbCellFlattenCellsFunc(scx, clientData) SearchContext *scx; /* Pointer to search context containing * ptr to cell use to be copied, * and transform to the target def. */ ClientData clientData; /* Data passed to client function */ { CellUse *use, *dest; int xMask; bool dolabels; bool toplabels; struct dbFlattenAllData *fad = (struct dbFlattenAllData *)clientData; dest = fad->fad_dest; xMask = fad->fad_xmask; dolabels = fad->fad_dolabels; toplabels = fad->fad_toplabels; use = scx->scx_use; DBFlattenInPlace(use, dest, xMask, dolabels, toplabels, FALSE); return 2; } /* *----------------------------------------------------------------------------- * * DBCellFlattenAllCells -- * * Flatten subcells from the tree rooted at scx->scx_use into the edit root * CellDef, transforming according to the transform in scx. * * Results: * None. * * Side effects: * Updates the paint planes in EditRootDef. * *----------------------------------------------------------------------------- */ void DBCellFlattenAllCells(scx, dest, xMask, dolabels, toplabels) SearchContext *scx; /* Describes root cell to search and transform * from root cell to coords of targetUse. */ CellUse *dest; /* CellUse to flatten into (usually EditCellUse) */ int xMask; /* Expansion state mask to be passed to * the flattening routine that determines * whether to do a shallow or deep flattening. */ bool dolabels; /* Option to flatten labels */ bool toplabels; /* Option to selectively flatten top-level labels */ { int dbCellFlattenCellsFunc(); struct dbFlattenAllData fad; fad.fad_dest = dest; fad.fad_xmask = xMask; fad.fad_dolabels = dolabels; fad.fad_toplabels = toplabels; DBTreeSrCells(scx, CU_DESCEND_ALL, dbCellFlattenCellsFunc, (ClientData)&fad); } /* Client data structure used by DBCellGenerateSubstrate() */ struct dbCopySubData { Plane *csd_plane; TileType csd_subtype; int csd_pNum; bool csd_modified; }; /* *----------------------------------------------------------------------------- * * DBCellGenerateSubstrate -- * * This function is used by the extraction code in ExtSubtree.c. * Paint substrate into the target use. Similar to DBCellCopyAllPaint(), * but it finds space tiles on the substrate plane and converts them to * a substrate type in the target, clipped to the cell boundary. This * allows the extraction to find and record all substrate regions, both * common (global substrate) and local (isolated substrate), without * requiring a physical substrate type to be drawn into all cells. * * Unlike normal paint copying, this can only be done by painting the * substrate type over the entire cell area and then erasing all areas * belonging to not-substrate types in the source. * * Returns: * Nothing. * * Side Effects: * Paints into the targetUse's CellDef. This only happens if two * conditions are met: * (1) The techfile has defined "substrate" * (2) The techfile defines a type corresponding to the substrate * * ---------------------------------------------------------------------------- */ Plane * DBCellGenerateSubstrate(scx, subType, notSubMask, subShieldMask, targetDef) SearchContext *scx; TileType subType; /* Substrate paint type */ TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */ TileTypeBitMask *subShieldMask; /* Mask of types that shield substrate */ CellDef *targetDef; { struct dbCopySubData csd; Plane *tempPlane; int plane; Rect rect; TileTypeBitMask allButSubMask; TileTypeBitMask defaultSubTypeMask; int dbEraseSubFunc(); int dbPaintSubFunc(); int dbEraseNonSub(); int dbCopySubFunc(); GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect); /* Clip to bounding box of the top level cell */ GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox); plane = DBPlane(subType); tempPlane = DBNewPlane((ClientData) TT_SPACE); DBClearPaintPlane(tempPlane); csd.csd_subtype = subType; csd.csd_plane = tempPlane; csd.csd_pNum = plane; csd.csd_modified = FALSE; /* The substrate type will be redefined to denote only areas of */ /* isolated substrate. The first step is to erase the default */ /* substrate everywhere so that it can be regenerated automatically */ /* Note: xMask is always zero, as this is only called from extract routines */ TTMaskSetOnlyType(&defaultSubTypeMask, subType); DBTreeSrTiles(scx, &defaultSubTypeMask, 0, dbEraseSubFunc, (ClientData)&csd); /* Next, paint the substrate type in the temporary plane over the */ /* area of all substrate shield types. */ DBTreeSrTiles(scx, subShieldMask, 0, dbPaintSubFunc, (ClientData)&csd); if (csd.csd_modified == FALSE) return NULL; /* Now erase all areas that are non-substrate types in the source */ DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd); /* Finally, copy the destination plane contents onto tempPlane, */ /* ignoring the substrate type. */ TTMaskZero(&allButSubMask); TTMaskSetMask(&allButSubMask, &DBAllButSpaceBits); TTMaskClearType(&allButSubMask, subType); DBSrPaintArea((Tile *)NULL, targetDef->cd_planes[plane], &TiPlaneRect, &allButSubMask, dbCopySubFunc, (ClientData)&csd); /* Now we have a plane where the substrate type has a strict */ /* definition that it always marks areas of isolated substrate but */ /* never areas of default substrate. Return this plane. */ return tempPlane; } /* *----------------------------------------------------------------------------- * * DBCellGenerateSimpleSubstrate -- * * This function is used by the extraction code in "extresist". * It is similar to DBCellGenerateSubstrate(), above. It finds space * tiles on the substrate plane and converts them to a substrate type * in the target, clipped to the cell boundary. This allows the * extraction to find and record all common (global) substrate regions, * without requiring a physical substrate type to be drawn into all cells. * * Unlike normal paint copying, this can only be done by painting the * substrate type over the entire cell area and then erasing all areas * belonging to not-substrate types in the source. * * Returns: * Nothing. * * Side Effects: * Paints into the targetUse's CellDef. This only happens if two * conditions are met: * (1) The techfile has defined "substrate" * (2) The techfile defines a type corresponding to the substrate * * ---------------------------------------------------------------------------- */ Plane * DBCellGenerateSimpleSubstrate(scx, subType, notSubMask, targetDef) SearchContext *scx; TileType subType; /* Substrate paint type */ TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */ CellDef *targetDef; { struct dbCopySubData csd; Plane *tempPlane; int plane; Rect rect; TileTypeBitMask allButSubMask; TileTypeBitMask defaultSubTypeMask; int dbEraseSubFunc(); int dbPaintSubFunc(); int dbEraseNonSub(); int dbCopySubFunc(); GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect); /* Clip to bounding box of the top level cell */ GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox); plane = DBPlane(subType); tempPlane = DBNewPlane((ClientData) TT_SPACE); DBClearPaintPlane(tempPlane); csd.csd_subtype = subType; csd.csd_plane = tempPlane; csd.csd_pNum = plane; csd.csd_modified = FALSE; /* Paint the substrate type in the temporary plane over the area of */ /* the entire cell. */ DBPaintPlane(tempPlane, &rect, DBStdPaintTbl(subType, plane), (PaintUndoInfo *)NULL); /* Now erase all areas that are non-substrate types in the source */ DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd); /* Finally, copy the destination plane contents onto tempPlane, */ /* ignoring the substrate type. */ TTMaskZero(&allButSubMask); TTMaskSetMask(&allButSubMask, &DBAllButSpaceBits); TTMaskClearType(&allButSubMask, subType); DBSrPaintArea((Tile *)NULL, targetDef->cd_planes[plane], &TiPlaneRect, &allButSubMask, dbCopySubFunc, (ClientData)&csd); /* Now we have a plane where the substrate type occupies the whole */ /* area of the cell except where there are conflicting types (e.g., */ /* nwell). Return this plane. */ return tempPlane; } /* * Callback function for DBCellGenerateSubstrate() * Finds tiles in the source def that belong to the type that represents * the substrate, and erases them. */ int dbEraseSubFunc(tile, cxp) Tile *tile; /* Pointer to source tile with shield type */ TreeContext *cxp; /* Context from DBTreeSrTiles */ { SearchContext *scx; Rect sourceRect, targetRect; int pNum; TileType dinfo, loctype, subType; Plane *plane; struct dbCopySubData *csd; /* Client data */ scx = cxp->tc_scx; csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; plane = csd->csd_plane; pNum = csd->csd_pNum; subType = csd->csd_subtype; dinfo = TiGetTypeExact(tile); if (IsSplit(tile)) { loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); if (loctype == TT_SPACE) return 0; dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans); } /* Construct the rect for the tile */ TITORECT(tile, &sourceRect); /* Transform to target coordinates */ GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); csd->csd_modified = TRUE; return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdEraseTbl(subType, pNum), (PaintUndoInfo *)NULL); } /* * Callback function for DBCellGenerateSubstrate() * Finds tiles in the source def that belong to the list of types that * shield the substrate (e.g., deep nwell), and paint the substrate type * into the target plane over the same area. */ int dbPaintSubFunc(tile, cxp) Tile *tile; /* Pointer to source tile with shield type */ TreeContext *cxp; /* Context from DBTreeSrTiles */ { SearchContext *scx; Rect sourceRect, targetRect; int pNum; TileType dinfo, loctype, subType; Plane *plane; struct dbCopySubData *csd; /* Client data */ scx = cxp->tc_scx; csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; plane = csd->csd_plane; pNum = csd->csd_pNum; subType = csd->csd_subtype; dinfo = TiGetTypeExact(tile); if (IsSplit(tile)) { loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); if (loctype == TT_SPACE) return 0; dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans); } /* Construct the rect for the tile */ TITORECT(tile, &sourceRect); /* Transform to target coordinates */ GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); csd->csd_modified = TRUE; return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdPaintTbl(subType, pNum), (PaintUndoInfo *)NULL); } /* * Callback function for DBCellGenerateSubstrate() * Finds tiles on the substrate plane in the source def that are not the * substrate type, and erases those areas from the target. This reduces * the geometry in the target plane to areas that form isolated substrate * regions. Regions belonging to the common global substrate are ignored. */ int dbEraseNonSub(tile, cxp) Tile *tile; /* Pointer to tile to erase from target */ TreeContext *cxp; /* Context from DBTreeSrTiles */ { SearchContext *scx; Rect sourceRect, targetRect; Plane *plane; /* Plane of target data */ TileType dinfo, loctype, subType; struct dbCopySubData *csd; int pNum; csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; plane = csd->csd_plane; subType = csd->csd_subtype; pNum = csd->csd_pNum; scx = cxp->tc_scx; dinfo = TiGetTypeExact(tile); if (IsSplit(tile)) { loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); if (loctype == TT_SPACE) return 0; dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans); } /* Construct the rect for the tile */ TITORECT(tile, &sourceRect); /* Transform to target coordinates */ GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); /* Erase the substrate type from the area of this tile in the target plane. */ return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdEraseTbl(subType, pNum), (PaintUndoInfo *)NULL); } /* * Callback function for DBCellGenerateSubstrate() * Simple paint function to copy all paint from the substrate plane of the * source def into the target plane containing the isolated substrate * regions. */ int dbCopySubFunc(tile, csd) Tile *tile; /* Pointer to tile to erase from target */ struct dbCopySubData *csd; /* Client data */ { Rect rect; int pNum; TileType type, loctype; Plane *plane; plane = csd->csd_plane; pNum = csd->csd_pNum; type = TiGetTypeExact(tile); if (IsSplit(tile)) { loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); if (loctype == TT_SPACE) return 0; } else loctype = type; /* Construct the rect for the tile */ TITORECT(tile, &rect); return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(loctype, pNum), (PaintUndoInfo *)NULL); } /* *----------------------------------------------------------------------------- * * DBCellCopyAllLabels -- * * Copy labels from the tree rooted at scx->scx_use to targetUse, * transforming according to the transform in scx. Only labels * attached to layers of the types specified by mask are copied. * The area to be copied is determined by GEO_LABEL_IN_AREA. * * Results: * None. * * Side effects: * Copies labels to targetUse, clipping against scx->scx_area. * If pArea is given, store in it the bounding box of all the * labels copied. * *----------------------------------------------------------------------------- */ void DBCellCopyAllLabels(scx, mask, xMask, targetUse, pArea) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Only labels of these types are copied */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which labels are to be stuffed */ Rect *pArea; /* If non-NULL, points to a box that will be * filled in with bbox (in targetUse coords) * of all labels copied. Will be degenerate * if nothing was copied. */ { int dbCopyAllLabels(); struct copyLabelArg arg; /* DBTeeSrLabels finds all the labels that we want plus some more. * We'll filter out the ones that we don't need. */ arg.cla_targetUse = targetUse; arg.cla_bbox = pArea; arg.cla_glob = NULL; if (pArea != NULL) { pArea->r_xbot = 0; pArea->r_xtop = -1; } (void) DBTreeSrLabels(scx, mask, xMask, (TerminalPath *) 0, TF_LABEL_ATTACH, dbCopyAllLabels, (ClientData) &arg); } /*ARGSUSED*/ int dbCopyAllLabels(scx, lab, tpath, arg) SearchContext *scx; Label *lab; TerminalPath *tpath; struct copyLabelArg *arg; { Rect labTargetRect; Point labOffset; int targetPos, labRotate; CellDef *def; def = arg->cla_targetUse->cu_def; if (arg->cla_glob != NULL) if (!Match(arg->cla_glob, lab->lab_text)) return 0; if (!GEO_LABEL_IN_AREA(&lab->lab_rect, &(scx->scx_area))) return 0; GeoTransRect(&scx->scx_trans, &lab->lab_rect, &labTargetRect); targetPos = GeoTransPos(&scx->scx_trans, lab->lab_just); GeoTransPointDelta(&scx->scx_trans, &lab->lab_offset, &labOffset); labRotate = GeoTransAngle(&scx->scx_trans, lab->lab_rotate); /* Eliminate duplicate labels. Don't pay any attention to layers * in deciding on duplicates: if text and position match, it's a * duplicate. */ DBEraseLabelsByContent(def, &labTargetRect, -1, lab->lab_text); DBPutFontLabel(def, &labTargetRect, lab->lab_font, lab->lab_size, labRotate, &labOffset, targetPos, lab->lab_text, lab->lab_type, lab->lab_flags, lab->lab_port); if (arg->cla_bbox != NULL) { GeoIncludeAll(&labTargetRect, arg->cla_bbox); /* Rendered font labels include the bounding box of the text itself */ if (lab->lab_font >= 0) { GeoTransRect(&scx->scx_trans, &lab->lab_bbox, &labTargetRect); GeoIncludeAll(&labTargetRect, arg->cla_bbox); } } return 0; } /* *----------------------------------------------------------------------------- * * DBCellCopyGlobLabels -- * * Copy labels from the tree rooted at scx->scx_use to targetUse, * transforming according to the transform in scx. Only labels * attached to layers of the types specified by mask and which * match the string "globmatch" by glob-style matching are copied. * The area to be copied is determined by GEO_LABEL_IN_AREA. * * Results: * None. * * Side effects: * Copies labels to targetUse, clipping against scx->scx_area. * If pArea is given, store in it the bounding box of all the * labels copied. * *----------------------------------------------------------------------------- */ void DBCellCopyGlobLabels(scx, mask, xMask, targetUse, pArea, globmatch) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Only labels of these types are copied */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which labels are to be stuffed */ Rect *pArea; /* If non-NULL, points to a box that will be * filled in with bbox (in targetUse coords) * of all labels copied. Will be degenerate * if nothing was copied. */ char *globmatch; /* If non-NULL, only labels matching this * string by glob-style matching are copied. */ { int dbCopyAllLabels(); struct copyLabelArg arg; /* DBTeeSrLabels finds all the labels that we want plus some more. * We'll filter out the ones that we don't need. */ arg.cla_targetUse = targetUse; arg.cla_bbox = pArea; arg.cla_glob = globmatch; if (pArea != NULL) { pArea->r_xbot = 0; pArea->r_xtop = -1; } (void) DBTreeSrLabels(scx, mask, xMask, (TerminalPath *) 0, TF_LABEL_ATTACH, dbCopyAllLabels, (ClientData) &arg); } /* *----------------------------------------------------------------------------- * * DBCellCopyPaint -- * * Copy paint from the paint planes of scx->scx_use to the paint planes * of targetUse, transforming according to the transform in scx. * Only the types specified by typeMask are copied. * * Results: * None. * * Side effects: * Updates the paint planes in targetUse. * *----------------------------------------------------------------------------- */ void DBCellCopyPaint(scx, mask, xMask, targetUse) SearchContext *scx; /* Describes cell to search, area to * copy, transform from cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which material is to be stuffed */ { int pNum; PlaneMask planeMask; TreeContext cxp; TreeFilter filter; struct copyAllArg arg; int dbCopyAllPaint(); if (!DBDescendSubcell(scx->scx_use, xMask)) return; arg.caa_mask = mask; arg.caa_targetUse = targetUse; arg.caa_func = NULL; GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); /* Build dummy TreeContext */ cxp.tc_scx = scx; cxp.tc_filter = &filter; filter.tf_arg = (ClientData) &arg; /* tf_func, tf_mask, tf_xmask, tf_planes, and tf_tpath are unneeded */ planeMask = DBTechTypesToPlanes(mask); for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) if (PlaneMaskHasPlane(planeMask, pNum)) { cxp.tc_plane = pNum; (void) DBSrPaintArea((Tile *) NULL, scx->scx_use->cu_def->cd_planes[pNum], &scx->scx_area, mask, dbCopyAllPaint, (ClientData) &cxp); } } /* *----------------------------------------------------------------------------- * * DBCellCopyLabels -- * * Copy labels from scx->scx_use to targetUse, transforming according to * the transform in scx. Only labels attached to layers of the types * specified by mask are copied. If mask contains the L_LABEL bit, then * all labels are copied regardless of their layer. The area copied is * determined by GEO_LABEL_IN_AREA. * * Results: * None. * * Side effects: * Updates the labels in targetUse. If pArea is given, it will * be filled in with the bounding box of all labels copied. * *----------------------------------------------------------------------------- */ void DBCellCopyLabels(scx, mask, xMask, targetUse, pArea) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ TileTypeBitMask *mask; /* Only labels of these types are copied */ int xMask; /* Expansion state mask to be used in search */ CellUse *targetUse; /* Cell into which labels are to be stuffed */ Rect *pArea; /* If non-NULL, points to rectangle to be * filled in with bbox (in targetUse coords) * of all labels copied. Will be degenerate * if no labels are copied. */ { Label *lab; CellDef *def = targetUse->cu_def; Rect labTargetRect; Rect *rect = &scx->scx_area; int targetPos, labRotate; Point labOffset; CellUse *sourceUse = scx->scx_use; if (pArea != NULL) { pArea->r_xbot = 0; pArea->r_xtop = -1; } if (!DBDescendSubcell(sourceUse, xMask)) return; for (lab = sourceUse->cu_def->cd_labels; lab; lab = lab->lab_next) if (GEO_LABEL_IN_AREA(&lab->lab_rect, rect) && (TTMaskHasType(mask, lab->lab_type) || TTMaskHasType(mask, L_LABEL))) { GeoTransRect(&scx->scx_trans, &lab->lab_rect, &labTargetRect); targetPos = GeoTransPos(&scx->scx_trans, lab->lab_just); GeoTransPointDelta(&scx->scx_trans, &lab->lab_offset, &labOffset); labRotate = GeoTransAngle(&scx->scx_trans, lab->lab_rotate); /* Eliminate duplicate labels. Don't pay any attention to * type when deciding on duplicates, since types can change * later and then we'd have a duplicate. */ DBEraseLabelsByContent(def, &labTargetRect, -1, lab->lab_text); DBPutFontLabel(def, &labTargetRect, lab->lab_font, lab->lab_size, labRotate, &labOffset, targetPos, lab->lab_text, lab->lab_type, lab->lab_flags, lab->lab_port); if (pArea != NULL) (void) GeoIncludeAll(&labTargetRect, pArea); } } /*** *** Filter function for paint: Ignores diagonal (split) tiles for *** purposes of selection searches. ***/ int dbCopyManhattanPaint(tile, cxp) Tile *tile; /* Pointer to tile to copy */ TreeContext *cxp; /* Context from DBTreeSrTiles */ { SearchContext *scx = cxp->tc_scx; struct copyAllArg *arg; Rect sourceRect, targetRect; PaintUndoInfo ui; CellDef *def; TileType type; int pNum = cxp->tc_plane; /* * Don't copy space tiles -- this copy is additive. * We should never get passed a space tile, though, because * the caller will be using DBSrPaintArea, so this is just * a sanity check. */ type = TiGetTypeExact(tile); if (type == TT_SPACE || (type & TT_DIAGONAL)) return 0; arg = (struct copyAllArg *) cxp->tc_filter->tf_arg; /* Construct the rect for the tile in source coordinates */ TITORECT(tile, &sourceRect); /* Transform to target coordinates */ GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); ui.pu_def = def = arg->caa_targetUse->cu_def; def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; /* Clip against the target area */ GEOCLIP(&targetRect, &arg->caa_rect); (*dbCurPaintPlane)(def, pNum, type, &targetRect, &ui); return (0); } /*** *** Filter function for paint ***/ int dbCopyAllPaint(tile, cxp) Tile *tile; /* Pointer to tile to copy */ TreeContext *cxp; /* Context from DBTreeSrTiles */ { SearchContext *scx = cxp->tc_scx; struct copyAllArg *arg; Rect sourceRect, targetRect; PaintUndoInfo ui; CellDef *def; TileType type = TiGetTypeExact(tile); int pNum = cxp->tc_plane; int result; TileTypeBitMask *typeMask; /* * Don't copy space tiles -- this copy is additive. * We should never get passed a space tile, though, because * the caller will be using DBSrPaintArea, so this is just * a sanity check. */ bool splittile = FALSE; TileType dinfo = 0; if (IsSplit(tile)) { splittile = TRUE; dinfo = DBTransformDiagonal(type, &scx->scx_trans); type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); } if (type == TT_SPACE) return 0; arg = (struct copyAllArg *) cxp->tc_filter->tf_arg; typeMask = arg->caa_mask; /* Resolve what type we're going to paint, based on the type and mask */ if (!TTMaskHasType(typeMask, type)) { TileTypeBitMask rMask, *tmask; /* Simple case---typeMask has a residue of type on pNum */ tmask = DBResidueMask(type); TTMaskAndMask3(&rMask, typeMask, tmask); TTMaskAndMask(&rMask, &DBPlaneTypes[pNum]); if (!TTMaskIsZero(&rMask)) { for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++) if (TTMaskHasType(&rMask, type)) break; if (type == DBNumUserLayers) return 0; /* shouldn't happen */ /* Hopefully there's always just one type here---sanity check */ TTMaskClearType(&rMask, type); if (!TTMaskIsZero(&rMask)) { /* Diagnostic */ TxError("Bad assumption: Multiple types to paint! Fix me!\n"); } } else { type = DBPlaneToResidue(type, pNum); if (!TTMaskHasType(typeMask, type)) return 0; } } /* Construct the rect for the tile in source coordinates */ TITORECT(tile, &sourceRect); /* Transform to target coordinates */ GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); ui.pu_def = def = arg->caa_targetUse->cu_def; def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; /* Nonmanhattan geometry requires slightly different handling. */ /* Paint the whole tile and clip by erasing areas outside the */ /* clipping rectangle. */ if (splittile) { Point points[5]; Rect rrect, orect; int np, i, j; GrClipTriangle(&targetRect, &arg->caa_rect, TRUE, dinfo, points, &np); if (np == 0) return(0); if (np >= 3) { for (i = 0; i < np; i++) { j = (i + 1) % np; if (points[i].p_x != points[j].p_x && points[i].p_y != points[j].p_y) { /* Break out the triangle */ rrect.r_xbot = points[i].p_x; rrect.r_xtop = points[j].p_x; rrect.r_ybot = points[i].p_y; rrect.r_ytop = points[j].p_y; GeoCanonicalRect(&rrect, &targetRect); break; } } if (i == np) /* Exactly one Manhattan rectangle */ { rrect.r_xbot = points[0].p_x; rrect.r_xtop = points[2].p_x; rrect.r_ybot = points[0].p_y; rrect.r_ytop = points[2].p_y; GeoCanonicalRect(&rrect, &targetRect); dinfo = 0; } else if (np >= 4) /* Process extra rectangles in the area */ { /* "orect" is the bounding box of the polygon returned */ /* by ClipTriangle. */ orect.r_xtop = orect.r_xbot = points[0].p_x; orect.r_ytop = orect.r_ybot = points[0].p_y; for (i = 0; i < np; i++) GeoIncludePoint(&points[i], &orect); /* Rectangle to left or right */ rrect.r_ybot = orect.r_ybot; rrect.r_ytop = orect.r_ytop; if (targetRect.r_xbot > orect.r_xbot) { rrect.r_xbot = orect.r_xbot; rrect.r_xtop = targetRect.r_xbot; } else if (targetRect.r_xtop < orect.r_xtop) { rrect.r_xtop = orect.r_xtop; rrect.r_xbot = targetRect.r_xtop; } else goto topbottom; (*dbCurPaintPlane)(def, pNum, type, &rrect, &ui); topbottom: /* Rectangle to top or bottom */ rrect.r_xbot = targetRect.r_xbot; rrect.r_xtop = targetRect.r_xtop; if (targetRect.r_ybot > orect.r_ybot) { rrect.r_ybot = orect.r_ybot; rrect.r_ytop = targetRect.r_ybot; } else if (targetRect.r_ytop < orect.r_ytop) { rrect.r_ytop = orect.r_ytop; rrect.r_ybot = targetRect.r_ytop; } else goto splitdone; (*dbCurPaintPlane)(def, pNum, type, &rrect, &ui); } } } else /* Clip against the target area */ GEOCLIP(&targetRect, &arg->caa_rect); splitdone: result = (*dbCurPaintPlane)(def, pNum, dinfo | type, &targetRect, &ui); if ((result != 0) && (arg->caa_func != NULL)) { /* result == 1 used exclusively for DRC off-grid error flagging */ DRCOffGridError(&targetRect); } return (0); } /* *----------------------------------------------------------------------------- * * DBCellCopyAllCells -- * * Copy unexpanded subcells from the tree rooted at scx->scx_use * to the subcell plane of targetUse, transforming according to * the transform in scx. * * This effectively "flattens" a cell hierarchy in the sense that * all unexpanded subcells in a region (which would appear in the * display as bounding boxes) are copied into targetUse without * regard for their original location in the hierarchy of scx->scx_use. * If an array is unexpanded, it is copied as an array, not as a * collection of individual cells. * * Results: * None. * * Side effects: * Updates the cell plane in targetUse. If pArea is given, it * will be filled in with the total area of all cells copied. * *----------------------------------------------------------------------------- */ void DBCellCopyAllCells(scx, xMask, targetUse, pArea) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from root cell to coords * of targetUse. */ CellUse *targetUse; /* Cell into which material is to be stuffed */ int xMask; /* Expansion state mask to be used in * searching. Cells not expanded according * to this mask are copied. To copy everything * in the subtree under scx->scx_use without * regard to expansion, pass a mask of 0. */ Rect *pArea; /* If non-NULL, points to a rectangle to be * filled in with bbox (in targetUse coords) * of all cells copied. Will be degenerate * if nothing was copied. */ { struct copyAllArg arg; int dbCellCopyCellsFunc(); arg.caa_targetUse = targetUse; arg.caa_bbox = pArea; if (pArea != NULL) { pArea->r_xbot = 0; /* Make bounding box empty initially. */ pArea->r_xtop = -1; } GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); (void) DBTreeSrCells(scx, xMask, dbCellCopyCellsFunc, (ClientData) &arg); /* dbCellCopyCellsFunc() allows cells to be left with duplicate IDs */ /* so generate unique IDs as needed now. */ if (targetUse != NULL) DBGenerateUniqueIds(targetUse->cu_def, FALSE); } /* *----------------------------------------------------------------------------- * * DBCellCopyCells -- * * Copy all subcells that are immediate children of scx->scx_use->cu_def * into the subcell plane of targetUse, transforming according to * the transform in scx. Arrays are copied as arrays, not as a * collection of individual cells. If a cell is already present in * targetUse that would be exactly duplicated by a new cell, the new * cell isn't copied. * * Results: * None. * * Side effects: * Updates the cell plane in targetUse. If pArea is given, it will * be filled in with the bounding box of all cells copied. * *----------------------------------------------------------------------------- */ void DBCellCopyCells(scx, targetUse, pArea) SearchContext *scx; /* Describes root cell to search, area to * copy, transform from coords of * scx->scx_use->cu_def to coords of targetUse. */ CellUse *targetUse; /* Cell into which material is to be stuffed */ Rect *pArea; /* If non-NULL, points to rectangle to be * filled in with bbox (in targetUse coords) * of all cells copied. Will be degenerate * if nothing was copied. */ { struct copyAllArg arg; int dbCellCopyCellsFunc(); arg.caa_targetUse = targetUse; arg.caa_bbox = pArea; if (pArea != NULL) { pArea->r_xbot = 0; pArea->r_xtop = -1; } GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); (void) DBCellSrArea(scx, dbCellCopyCellsFunc, (ClientData) &arg); } /* *----------------------------------------------------------------------------- * * dbCellCopyCellsFunc -- * * Do the actual work of yanking cells for DBCellCopyAllCells() and * DBCellCopyCells() above. * * Results: * Always return 2. * * Side effects: * Updates the cell plane in arg->caa_targetUse->cu_def. * *----------------------------------------------------------------------------- */ int dbCellCopyCellsFunc(scx, arg) SearchContext *scx; /* Pointer to search context containing * ptr to cell use to be copied, * and transform to the target def. */ struct copyAllArg *arg; /* Client data from caller */ { CellUse *use, *newUse; CellDef *def; int xsep, ysep, xbase, ybase; Transform newTrans; use = scx->scx_use; def = use->cu_def; /* Don't allow circular structures! */ if (DBIsAncestor(def, arg->caa_targetUse->cu_def)) { TxPrintf("Copying %s would create a circularity in the", def->cd_name); TxPrintf(" cell hierarchy \n(%s is already its ancestor)", arg->caa_targetUse->cu_def->cd_name); TxPrintf(" so cell not copied.\n"); return 2; } /* When creating a new use, re-use the id from the old one. */ /* Do not attempt to run DBLinkCell() now and resolve unique IDs; */ /* just create duplicate IDs and regenerate unique ones at the end. */ newUse = DBCellNewUse(def, (char *) use->cu_id); newUse->cu_expandMask = use->cu_expandMask; newUse->cu_flags = use->cu_flags; /* The translation stuff is funny, since we got one element of * the array, but not necessarily the lower-left element. To * get the transform for the array as a whole, subtract off fo * the index of the element. The easiest way to see how this * works is to look at the code in dbCellSrFunc; the stuff here * is the opposite. */ if (use->cu_xlo > use->cu_xhi) xsep = -use->cu_xsep; else xsep = use->cu_xsep; if (use->cu_ylo > use->cu_yhi) ysep = -use->cu_ysep; else ysep = use->cu_ysep; xbase = xsep * (scx->scx_x - use->cu_xlo); ybase = ysep * (scx->scx_y - use->cu_ylo); GeoTransTranslate(-xbase, -ybase, &scx->scx_trans, &newTrans); DBSetArray(use, newUse); DBSetTrans(newUse, &newTrans); if (DBCellFindDup(newUse, arg->caa_targetUse->cu_def) != NULL) { if (!(arg->caa_targetUse->cu_def->cd_flags & CDINTERNAL)) { TxError("Cell \"%s\" would end up on top of an identical copy\n", newUse->cu_id); TxError(" of itself. I'm going to forget about the"); TxError(" new copy.\n"); } DBUnLinkCell(newUse, arg->caa_targetUse->cu_def); (void) DBCellDeleteUse(newUse); } else { DBPlaceCell(newUse, arg->caa_targetUse->cu_def); if (arg->caa_bbox != NULL) (void) GeoIncludeAll(&newUse->cu_bbox, arg->caa_bbox); } return 2; } /* * ---------------------------------------------------------------------------- * * DBNewPaintTable -- * * This procedure changes the paint table to be used by the * DBCellCopyPaint and DBCellCopyAllPaint procedures. * * Results: * The return value is the address of the paint table that used * to be in effect. It is up to the client to restore this * value with another call to this procedure. * * Side effects: * A new paint table takes effect. However, if newTable is NULL, * then the old paint table remains active. This allows one to * get a pointer to the active paint table without altering it. * * ---------------------------------------------------------------------------- */ PaintResultType (* DBNewPaintTable(newTable))[NT][NT] PaintResultType (*newTable)[NT][NT]; /* Address of new paint table. */ { PaintResultType (*oldTable)[NT][NT] = dbCurPaintTbl; if (newTable) dbCurPaintTbl = newTable; return oldTable; } /* * ---------------------------------------------------------------------------- * * DBNewPaintPlane -- * * This procedure changes the painting procedure to be used by the * DBCellCopyPaint and DBCellCopyAllPaint procedures. * * Results: * The return value is the address of the paint procedure that * used to be in effect. It is up to the client to restore this * value with another call to this procedure. * * Side effects: * A new paint procedure takes effect. * * ---------------------------------------------------------------------------- */ IntProc DBNewPaintPlane(newProc) int (*newProc)(); /* Address of new procedure */ { int (*oldProc)() = dbCurPaintPlane; dbCurPaintPlane = newProc; return (oldProc); }