Files
magic/database/DBcellsrch.c
T
Tim Edwards 088fc759c4 Set of changes updating version 8.2 to the level of 8.1, since 8.2
development had been halted since it was first created back in April.
Version 8.2 is now the official development version, with the first
development push to create a Cairo graphics interface.
2017-08-01 22:14:42 -04:00

1887 lines
53 KiB
C

/*
* DBcellsearch.c --
*
* Area searching which spans cell boundaries.
*
* *********************************************************************
* * 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/DBcellsrch.c,v 1.7 2010/09/15 21:53:22 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/malloc.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "textio/textio.h"
#include "utils/signals.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "mzrouter/mzrouter.h"
/* Quick hack for dbScalePlanes() access to the CIF/GDS paint table */
#ifdef CIF_MODULE
extern PaintResultType CIFPaintTable[];
#endif
/*
* The following structure is used to accumulate information about
* the types of tiles visible underneath a given point in the database.
*/
struct seeTypesArg
{
TileTypeBitMask *saa_mask; /* Mask of tile types seen in search */
Rect *saa_rect; /* Search area in root coordinates */
};
/*
*-----------------------------------------------------------------------------
*
* DBTreeSrTiles --
*
* Recursively search downward from the supplied CellUse for
* all visible paint tiles matching the supplied type mask.
*
* The procedure should be of the following form:
* int
* func(tile, cxp)
* Tile *tile;
* TreeContext *cxp;
* {
* }
*
* The SearchContext is stored in cxp->tc_scx, and the user's arg is stored
* in cxp->tc_filter->tf_arg.
*
* In the above, the scx transform is the net transform from the coordinates
* of tile to "world" coordinates (or whatever coordinates the initial
* transform supplied to DBTreeSrTiles was a transform to). Func returns
* 0 under normal conditions. If 1 is returned, it is a request to
* abort the search.
*
* *** WARNING ***
*
* The client procedure should not modify any of the paint planes in
* the cells visited by DBTreeSrTiles, because we use DBSrPaintArea
* instead of TiSrArea as our paint-tile enumeration function.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBTreeSrTiles(scx, mask, xMask, func, cdarg)
SearchContext *scx; /* Pointer to search context specifying
* a cell use to search, an area in the
* coordinates of the cell's def, and a
* transform back to "root" coordinates.
*/
TileTypeBitMask *mask; /* Only tiles with a type for which
* a bit in this mask is on are processed.
*/
int xMask; /* All subcells are visited recursively
* until we encounter uses whose flags,
* when anded with xMask, are not
* equal to xMask.
*/
int (*func)(); /* Function to apply at each qualifying tile */
ClientData cdarg; /* Client data for above function */
{
int dbCellTileSrFunc();
TreeFilter filter;
/* Set up the filter and call the recursive filter function */
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
filter.tf_xmask = xMask;
filter.tf_dinfo = 0;
filter.tf_planes = DBTechTypesToPlanes(mask);
return dbCellTileSrFunc(scx, &filter);
}
/*
* DBTreeSrNMTiles --
* This is a variant of the above in which the search is over
* a non-Manhattan area.
*/
int
DBTreeSrNMTiles(scx, dinfo, mask, xMask, func, cdarg)
SearchContext *scx; /* Pointer to search context specifying
* a cell use to search, an area in the
* coordinates of the cell's def, and a
* transform back to "root" coordinates.
*/
TileType dinfo; /* Type containing information about the
* diagonal area to search.
*/
TileTypeBitMask *mask; /* Only tiles with a type for which
* a bit in this mask is on are processed.
*/
int xMask; /* All subcells are visited recursively
* until we encounter uses whose flags,
* when anded with xMask, are not
* equal to xMask.
*/
int (*func)(); /* Function to apply at each qualifying tile */
ClientData cdarg; /* Client data for above function */
{
int dbCellTileSrFunc();
TreeFilter filter;
/* Set up the filter and call the recursive filter function */
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
filter.tf_xmask = xMask;
filter.tf_dinfo = dinfo;
filter.tf_planes = DBTechTypesToPlanes(mask);
return dbCellTileSrFunc(scx, &filter);
}
/*
* dbCellTileSrFunc --
*
* Recursive filter procedure applied to the cell by DBTreeSrTiles().
*/
int
dbCellTileSrFunc(scx, fp)
SearchContext *scx;
TreeFilter *fp;
{
TreeContext context;
CellDef *def = scx->scx_use->cu_def;
int pNum;
ASSERT(def != (CellDef *) NULL, "dbCellTileSrFunc");
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
return 0;
if ((def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
context.tc_scx = scx;
context.tc_filter = fp;
/*
* Apply the function first to any of the tiles in the planes
* for this CellUse's CellDef that match the mask.
*/
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(fp->tf_planes, pNum))
{
context.tc_plane = pNum;
if (fp->tf_dinfo & TT_DIAGONAL)
{
// TileType dinfo = DBTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
TileType dinfo = DBInvTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
dinfo, &scx->scx_area, fp->tf_mask,
fp->tf_func, (ClientData) &context))
return 1;
}
else if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
&scx->scx_area, fp->tf_mask,
fp->tf_func, (ClientData) &context))
return 1;
}
/*
* Now apply ourselves recursively to each of the CellUses
* in our tile plane.
*/
if (DBCellSrArea(scx, dbCellTileSrFunc, (ClientData) fp))
return 1;
else return 0;
}
/*
*-----------------------------------------------------------------------------
*
* DBTreeSrUniqueTiles --
*
* Recursively search downward from the supplied CellUse for
* all visible paint tiles matching the supplied type mask.
* This routine is like DBTreeSrTiles, above, except that it will
* only call the specified routine ONCE for each contact type, in
* the home plane of that contact type. Stacked contact types will
* only be processed if the current search plane matches the home
* plane of one of the stacked contact type's residues.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBTreeSrUniqueTiles(scx, mask, xMask, func, cdarg)
SearchContext *scx; /* Pointer to search context specifying
* a cell use to search, an area in the
* coordinates of the cell's def, and a
* transform back to "root" coordinates.
*/
TileTypeBitMask *mask; /* Only tiles with a type for which
* a bit in this mask is on are processed.
*/
int xMask; /* All subcells are visited recursively
* until we encounter uses whose flags,
* when anded with xMask, are not
* equal to xMask.
*/
int (*func)(); /* Function to apply at each qualifying tile */
ClientData cdarg; /* Client data for above function */
{
int dbCellTileSrFunc();
TreeFilter filter;
/* Set up the filter and call the recursive filter function */
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
filter.tf_xmask = xMask;
filter.tf_planes = DBTechTypesToPlanes(mask);
return dbCellUniqueTileSrFunc(scx, &filter);
}
/*
* dbCellUniqueTileSrFunc --
*
* Recursive filter procedure applied to the cell by DBTreeSrUniqueTiles().
* This is similar to dbCellTileSrFunc, except that for each plane searched,
* only the tile types having that plane as their home plane will be passed
* to the filter function. Contacts will therefore be processed only once.
*/
int
dbCellUniqueTileSrFunc(scx, fp)
SearchContext *scx;
TreeFilter *fp;
{
TreeContext context;
TileTypeBitMask uMask;
CellDef *def = scx->scx_use->cu_def;
int pNum;
ASSERT(def != (CellDef *) NULL, "dbCellUniqueTileSrFunc");
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
return 0;
if ((def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
context.tc_scx = scx;
context.tc_filter = fp;
/*
* Apply the function first to any of the tiles in the planes
* for this CellUse's CellDef that match the mask.
*/
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(fp->tf_planes, pNum))
{
uMask = DBHomePlaneTypes[pNum];
TTMaskAndMask(&uMask, fp->tf_mask);
if (!TTMaskIsZero(&uMask))
{
context.tc_plane = pNum;
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
&scx->scx_area, &uMask, fp->tf_func,
(ClientData) &context))
return 1;
}
}
/*
* Now apply ourselves recursively to each of the CellUses
* in our tile plane.
*/
if (DBCellSrArea(scx, dbCellUniqueTileSrFunc, (ClientData) fp))
return 1;
else return 0;
}
/*
*-----------------------------------------------------------------------------
*
* DBNoTreeSrTiles --
*
* (*** Move to database module after tested)
*
* NOTE: THIS PROCEDURE IS EXACTLY LIKE DBTreeSrTiles EXCEPT THAT IT DOES
* NOT SEARCH SUBCELLS.
*
* Searches the supplied CellUse (if expanded) for
* all visible paint tiles matching the supplied type mask.
*
* The procedure should be of the following form:
* int
* func(tile, cxp)
* Tile *tile;
* TreeContext *cxp;
* {
* }
*
* The SearchContext is stored in cxp->tc_scx, and the user's arg is stored
* in cxp->tc_filter->tf_arg.
*
* In the above, the scx transform is the net transform from the coordinates
* of tile to "world" coordinates (or whatever coordinates the initial
* transform supplied to DBTreeSrTiles was a transform to). Func returns
* 0 under normal conditions. If 1 is returned, it is a request to
* abort the search.
*
* *** WARNING ***
*
* The client procedure should not modify any of the paint planes in
* the cells visited by DBTreeSrTiles, because we use DBSrPaintArea
* instead of TiSrArea as our paint-tile enumeration function.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBNoTreeSrTiles(scx, mask, xMask, func, cdarg)
SearchContext *scx; /* Pointer to search context specifying
* a cell use to search, an area in the
* coordinates of the cell's def, and a
* transform back to "root" coordinates.
*/
TileTypeBitMask *mask; /* Only tiles with a type for which
* a bit in this mask is on are processed.
*/
int xMask; /* All subcells are visited recursively
* until we encounter uses whose flags,
* when anded with xMask, are not
* equal to xMask.
*/
int (*func)(); /* Function to apply at each qualifying tile */
ClientData cdarg; /* Client data for above function */
{
TreeContext context;
TreeFilter filter;
CellUse *cellUse = scx->scx_use;
CellDef *def = cellUse->cu_def;
int pNum;
ASSERT(def != (CellDef *) NULL, "DBNoTreeSrTiles");
if (!DBDescendSubcell(cellUse, xMask))
return 0;
if ((def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
filter.tf_xmask = xMask;
filter.tf_planes = DBTechTypesToPlanes(mask);
context.tc_scx = scx;
context.tc_filter = &filter;
/*
* Apply the function first to any of the tiles in the planes
* for this CellUse's CellDef that match the mask.
*/
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(filter.tf_planes, pNum))
{
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
&scx->scx_area, mask, func, (ClientData) &context))
return 1;
}
/* Return normally */
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* DBTreeSrLabels --
*
* Recursively search downward from the supplied CellUse for
* all visible labels attached to layers matching the supplied
* type mask.
*
* The procedure should be of the following form:
* int
* func(scx, label, tpath, cdarg)
* SearchContext *scx;
* Label *label;
* TerminalPath *tpath;
* ClientData cdarg;
* {
* }
*
* In the above, the use associated with scx is the parent of the
* CellDef containing the tile which contains the label, and the
* transform associated is the net transform from the coordinates
* of the tile to "root" coordinates. Func normally returns 0. If
* func returns 1, it is a request to abort the search without finding
* any more labels.
*
* Results:
* 0 is returned if the search terminated normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
SearchContext *scx; /* Pointer to search context specifying
* a cell use to search, an area in the
* coordinates of the cell's def, and a
* transform back to "root" coordinates.
* The area may have zero size. Labels
* need only touch the area.
*/
TileTypeBitMask * mask; /* Only visit labels attached to these types */
int xMask; /* All subcells are visited recursively
* until we encounter uses whose flags,
* when anded with xMask, are not
* equal to xMask.
*/
TerminalPath *tpath; /* Pointer to a structure describing a
* partially filled in terminal pathname.
* If this pointer is NULL, we don't bother
* filling it in further; otherwise, we add
* new pathname components as we encounter
* them.
*/
unsigned char flags; /* Flags to denote whether labels should be
* searched according to the area of the
* attachment, the area of the label itself,
* or both.
*/
int (*func)(); /* Function to apply at each qualifying tile */
ClientData cdarg; /* Client data for above function */
{
SearchContext scx2;
Label *lab;
Rect *r = &scx->scx_area;
CellUse *cellUse = scx->scx_use;
CellDef *def = cellUse->cu_def;
TreeFilter filter;
bool is_touching;
int dbCellLabelSrFunc();
ASSERT(def != (CellDef *) NULL, "DBTreeSrLabels");
if (!DBDescendSubcell(cellUse, xMask)) return 0;
if ((def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
for (lab = def->cd_labels; lab; lab = lab->lab_next)
{
if (SigInterruptPending) break;
is_touching = FALSE;
if ((lab->lab_font < 0) || (flags & TF_LABEL_ATTACH))
{
/* For non-manhattan searches, label must be in or */
/* touch the triangle. (to-do: needs a proper */
/* insideness test) */
if (flags & TF_LABEL_ATTACH_CORNER)
{
Rect r1 = *r;
Rect r2 = *r;
if (flags & TF_LABEL_ATTACH_NOT_NE)
{
r1.r_ytop = r->r_ybot;
r2.r_xtop = r->r_xbot;
}
else if (flags & TF_LABEL_ATTACH_NOT_NW)
{
r1.r_ytop = r->r_ybot;
r2.r_xbot = r->r_xtop;
}
else if (flags & TF_LABEL_ATTACH_NOT_SE)
{
r1.r_ybot = r->r_ytop;
r2.r_xtop = r->r_xbot;
}
else if (flags & TF_LABEL_ATTACH_NOT_SW)
{
r1.r_ybot = r->r_ytop;
r2.r_xbot = r->r_xtop;
}
is_touching = GEO_TOUCH(&lab->lab_bbox, &r1) ||
GEO_TOUCH(&lab->lab_bbox, &r2);
}
else
is_touching = GEO_TOUCH(&lab->lab_rect, r);
}
if (!is_touching && (flags & TF_LABEL_DISPLAY) && (lab->lab_font >= 0))
is_touching = GEO_TOUCH(&lab->lab_bbox, r);
if (is_touching && TTMaskHasType(mask, lab->lab_type))
if ((*func)(scx, lab, tpath, cdarg))
return (1);
}
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
filter.tf_xmask = xMask;
filter.tf_tpath = tpath;
filter.tf_flags = flags;
/* filter.tf_planes is unused */
/* Visit each child CellUse recursively.
* This code is a bit tricky because the area can have zero size.
* This would cause subcells never to be examined. What we do is
* to expand the area by 1 here, then require the labels to OVERLAP
* instead of just TOUCH. Be careful when expanding: can't expand
* any coordinate past infinity.
*/
scx2 = *scx;
if (scx2.scx_area.r_xbot > TiPlaneRect.r_xbot) scx2.scx_area.r_xbot -= 1;
if (scx2.scx_area.r_ybot > TiPlaneRect.r_ybot) scx2.scx_area.r_ybot -= 1;
if (scx2.scx_area.r_xtop < TiPlaneRect.r_xtop) scx2.scx_area.r_xtop += 1;
if (scx2.scx_area.r_ytop < TiPlaneRect.r_ytop) scx2.scx_area.r_ytop += 1;
if (DBCellSrArea(&scx2, dbCellLabelSrFunc, (ClientData) &filter))
return 1;
return 0;
}
/*
* dbCellLabelSrFunc --
*
* Filter procedure applied to subcells by DBTreeSrLabels().
*/
int
dbCellLabelSrFunc(scx, fp)
SearchContext *scx;
TreeFilter *fp;
{
Label *lab;
Rect *r = &scx->scx_area;
TileTypeBitMask *mask = fp->tf_mask;
CellDef *def = scx->scx_use->cu_def;
char *tnext;
int result;
bool has_overlap;
ASSERT(def != (CellDef *) NULL, "dbCellLabelSrFunc");
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask)) return 0;
if ((def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
if (fp->tf_tpath != (TerminalPath *) NULL)
{
TerminalPath *tp = fp->tf_tpath;
tnext = tp->tp_next;
tp->tp_next = DBPrintUseId(scx, tp->tp_next, tp->tp_last-tp->tp_next,
FALSE);
if (tp->tp_next < tp->tp_last)
{
*(tp->tp_next++) = '/';
*(tp->tp_next) = '\0';
}
}
/* Apply the function first to any of the labels in this def. */
result = 0;
for (lab = def->cd_labels; lab; lab = lab->lab_next)
{
has_overlap = FALSE;
if ((lab->lab_font < 0) || (fp->tf_flags & TF_LABEL_ATTACH))
has_overlap = GEO_OVERLAP(&lab->lab_rect, r);
if (!has_overlap && (fp->tf_flags & TF_LABEL_DISPLAY) && (lab->lab_font >= 0))
has_overlap = GEO_OVERLAP(&lab->lab_bbox, r);
if (has_overlap && TTMaskHasType(mask, lab->lab_type))
{
if ((*fp->tf_func)(scx, lab, fp->tf_tpath, fp->tf_arg))
{
result = 1;
goto cleanup;
}
}
}
/* Now visit each child use recursively */
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
result = 1;
cleanup:
/* Remove the trailing pathname component from the TerminalPath */
if (fp->tf_tpath != (TerminalPath *) NULL)
{
fp->tf_tpath->tp_next = tnext;
*tnext = '\0';
}
return (result);
}
/*
*-----------------------------------------------------------------------------
*
* DBTreeSrCells --
*
* Recursively search downward from the supplied CellUse for
* all CellUses whose parents are expanded but which themselves
* are unexpanded.
*
* The procedure should be of the following form:
* int
* func(scx, cdarg)
* SearchContext *scx;
* ClientData cdarg;
* {
* }
*
* In the above, the transform scx->scx_trans is from coordinates of
* the def of scx->scx_use to the "root". The array indices
* scx->scx_x and scx->scx_y identify this element if it is a
* component of an array. Func normally returns 0. If func returns
* 1, then the search is aborted. If func returns 2, then all
* remaining elements of the current array are skipped, but the
* search is not aborted.
*
* Each element of an array is returned separately.
*
* Results:
* 0 is returned if the search terminated normally. 1 is
* returned if it was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBTreeSrCells(scx, xMask, func, cdarg)
SearchContext *scx; /* Pointer to search context specifying a cell use to
* search, an area in the coordinates of the cell's
* def, and a transform back to "root" coordinates.
*/
int xMask; /* All subcells are visited recursively until we
* encounter uses whose flags, when anded with
* xMask, are not equal to xMask. Func is called
* for these cells. A zero mask means all cells in
* the root use are considered not to be expanded,
* and hence are passed to func.
*/
int (*func)(); /* Function to apply to each qualifying cell */
ClientData cdarg; /* Client data for above function */
{
int dbTreeCellSrFunc();
CellUse *cellUse = scx->scx_use;
TreeContext context;
TreeFilter filter;
if (!DBDescendSubcell(cellUse, xMask))
return 0;
if ((cellUse->cu_def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(cellUse->cu_def, (char *) NULL, TRUE, NULL))
return 0;
context.tc_scx = scx;
context.tc_filter = &filter;
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_xmask = xMask;
if (DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) &filter))
return 1;
else return 0;
}
/*
* dbTreeCellSrFunc --
*
* Filter procedure applied to subcells by DBTreeSrCells().
*/
/*ARGSUSED*/
int
dbTreeCellSrFunc(scx, fp)
SearchContext *scx; /* Pointer to context containing a
* CellUse and a transform from coord-
* inates of the def of the use to the
* "root" of the search.
*/
TreeFilter *fp;
{
CellUse *use = scx->scx_use;
int result;
/* DBDescendSubcell treats a zero expand mask as "expanded everywhere",
* whereas we want it to mean "expanded nowhere". Handle specially.
*/
if ((fp->tf_xmask == CU_DESCEND_NO_LOCK) && (use->cu_flags & CU_LOCKED))
return 2;
else if ((!DBDescendSubcell(use, fp->tf_xmask)) ||
(fp->tf_xmask == CU_DESCEND_ALL))
result = (*fp->tf_func)(scx, fp->tf_arg);
else
{
if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, NULL))
return 0;
result = DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) fp);
}
return result;
}
/*
*-----------------------------------------------------------------------------
*
* DBSeeTypesAll --
*
* Set a TileTypeBitMask of all visible tiles beneath the given rectangle.
* "Beneath" in this case means "completely containing".
* The search takes place recursively down to all expanded cells beneath
* rootUse.
*
* Results:
* None.
*
* Side effects:
* Sets the TileTypeBitMask pointed to by 'mask' to all types beneath
* the rectangle.
*
*-----------------------------------------------------------------------------
*/
void
DBSeeTypesAll(rootUse, rootRect, xMask, mask)
CellUse *rootUse; /* CellUse from which to begin search */
Rect *rootRect; /* Clipping rectangle in coordinates of CellUse's def */
int xMask; /* Expansion mask for DBTreeSrTiles() */
TileTypeBitMask *mask; /* Mask to set */
{
int dbSeeTypesAllSrFunc();
SearchContext scontext;
scontext.scx_use = rootUse;
scontext.scx_trans = GeoIdentityTransform;
scontext.scx_area = *rootRect;
TTMaskZero(mask);
(void) DBTreeSrTiles(&scontext, &DBAllTypeBits, xMask,
dbSeeTypesAllSrFunc, (ClientData) mask);
}
/*
* dbSeeTypesAllSrFunc --
*
* Filter procedure applied to tiles by DBSeeTypesAll() above.
*/
int
dbSeeTypesAllSrFunc(tile, cxp)
Tile *tile;
TreeContext *cxp;
{
Rect tileRect;
TileTypeBitMask *mask = (TileTypeBitMask *) cxp->tc_filter->tf_arg;
Rect *area = &cxp->tc_scx->scx_area;
TiToRect(tile, &tileRect);
if (GEO_OVERLAP((&tileRect), area))
{
if (IsSplit(tile))
TTMaskSetType(mask, SplitSide(tile) ?
SplitRightType(tile) : SplitLeftType(tile));
else
TTMaskSetType(mask, TiGetType(tile));
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* DBSrRoots --
*
* Apply the supplied procedure to each CellUse that is a root of
* the given base CellDef. A root is a CellUse with no parent def.
*
* The procedure should be of the following form:
* int
* func(cellUse, transform, cdarg)
* CellUse *cellUse;
* Transform *transform;
* ClientData cdarg;
* {
* }
*
* Transform is from coordinates of baseDef to those of the def of cellUse.
* Func normally returns 0. If it returns 1 then the search is aborted.
*
* Results:
* 0 is returned if the search terminated normally. 1 is returned
* if it was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBSrRoots(baseDef, transform, func, cdarg)
CellDef *baseDef; /* Base CellDef, all of whose ancestors are
* searched for.
*/
Transform *transform; /* Transform from original baseDef to current
* baseDef.
*/
int (*func)(); /* Function to apply at each root cellUse */
ClientData cdarg; /* Client data for above function */
{
CellUse *parentUse;
int xoff, yoff, x, y;
Transform baseToParent, t;
if (baseDef == (CellDef *) NULL)
return 0;
for (parentUse = baseDef->cd_parents; parentUse != NULL;
parentUse = parentUse->cu_nextuse)
{
if (SigInterruptPending) return 1;
if (parentUse->cu_parent == (CellDef *) NULL)
{
GeoTransTrans(transform, &parentUse->cu_transform, &baseToParent);
if ((*func)(parentUse, &baseToParent, cdarg)) return 1;
}
else
{
for (x = parentUse->cu_xlo; x <= parentUse->cu_xhi; x++)
for (y = parentUse->cu_ylo; y <= parentUse->cu_yhi; y++)
{
if (SigInterruptPending)
return 1;
xoff = (x - parentUse->cu_xlo) * parentUse->cu_xsep;
yoff = (y - parentUse->cu_ylo) * parentUse->cu_ysep;
GeoTranslateTrans(transform, xoff, yoff, &t);
GeoTransTrans(&t, &parentUse->cu_transform, &baseToParent);
if (DBSrRoots(parentUse->cu_parent, &baseToParent,
func, cdarg)) return 1;
}
}
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* DBIsAncestor --
*
* Determine if cellDef1 is an ancestor of cellDef2.
*
* Results:
* TRUE if cellDef1 is an ancestor of cellDef2, FALSE if not.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
bool
DBIsAncestor(cellDef1, cellDef2)
CellDef *cellDef1; /* Potential ancestor */
CellDef *cellDef2; /* Potential descendant -- this is where we
* start the search.
*/
{
CellUse *parentUse;
CellDef *parentDef;
if (cellDef1 == cellDef2)
return (TRUE);
for (parentUse = cellDef2->cd_parents; parentUse != NULL;
parentUse = parentUse->cu_nextuse)
{
if ((parentDef = parentUse->cu_parent) != (CellDef *) NULL)
if (DBIsAncestor(cellDef1, parentDef))
return (TRUE);
}
return (FALSE);
}
/*
*-----------------------------------------------------------------------------
*
* DBCellSrArea --
*
* Apply the supplied procedure to each of the cellUses found in the
* given area in the subcell plane of the child def of the supplied
* search context.
*
* The procedure is applied to each array element in each cell use that
* overlaps the clipping rectangle. The scx_x and scx_y parts of
* the SearchContext passed to the filter function correspond to the
* array element being visited. The same CellUse is, of course, passed
* as scx_use for all elements of the array.
*
* The array elements are visited by varying the X coordinate fastest.
*
* The procedure should be of the following form:
* int
* func(scx, cdarg)
* SearchContext *scx;
* ClientData cdarg;
* {
* }
*
* Func normally returns 0. If it returns 1 then the search is
* aborted. If it returns 2, then any remaining elements in the
* current array are skipped.
*
* Results:
* 0 is returned if the search terminated normally. 1 is
* returned if it was aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBCellSrArea(scx, func, cdarg)
SearchContext *scx;
/* Pointer to search context specifying a cell use to
* search, an area in the coordinates of the cell's
* def, and a transform back to "root" coordinates.
* The area may have zero size.
*/
int (*func)(); /* Function to apply at every tile found */
ClientData cdarg; /* Argument to pass to function */
{
TreeFilter filter;
TreeContext context;
Rect expanded;
int dbCellSrFunc();
filter.tf_func = func;
filter.tf_arg = cdarg;
context.tc_filter = &filter;
context.tc_scx = scx;
if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, NULL))
return 0;
/* In order to make this work with zero-size areas, we first expand
* the area by before searching the tile plane. DbCellSrFunc will
* check carefully to throw out things that don't overlap the original
* area. The expansion is tricky because we mustn't expand infinities.
*/
expanded = scx->scx_area;
if (expanded.r_xbot > TiPlaneRect.r_xbot) expanded.r_xbot -= 1;
if (expanded.r_ybot > TiPlaneRect.r_ybot) expanded.r_ybot -= 1;
if (expanded.r_xtop < TiPlaneRect.r_xtop) expanded.r_xtop += 1;
if (expanded.r_ytop < TiPlaneRect.r_ytop) expanded.r_ytop += 1;
if (TiSrArea((Tile *) NULL, scx->scx_use->cu_def->cd_planes[PL_CELL],
&expanded, dbCellSrFunc, (ClientData) &context))
return 1;
else return 0;
}
/*
*-----------------------------------------------------------------------------
*
* dbCellSrFunc --
*
* Filter procedure for DBCellSrArea. Applies the procedure given
* to DBCellSrArea to any of the CellUses in the tile that are
* enumerable.
*
* Since subcells are allowed to overlap, a single tile body may
* refer to many subcells and a single subcell may be referred to
* by many tile bodies. To insure that each CellUse is enumerated
* exactly once, the procedure given to DBCellSrArea is only applied
* to a CellUse when its lower right corner is contained in the
* tile to dbCellSrFunc (or otherwise at the last tile encountered
* in the event the lower right corner of the CellUse is outside the
* search rectangle).
*
* Results:
* 0 is normally returned, and 1 is returned if an abort occurred.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
dbCellSrFunc(tile, cxp)
Tile *tile;
TreeContext *cxp;
{
TreeFilter *fp = cxp->tc_filter;
SearchContext *scx = cxp->tc_scx;
CellUse *use;
Rect *bbox;
CellTileBody *body;
SearchContext newScx;
Transform t, tinv;
Rect tileArea;
int srchBot, srchRight;
int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep, clientResult;
srchBot = scx->scx_area.r_ybot;
srchRight = scx->scx_area.r_xtop;
TITORECT(tile, &tileArea);
/* Make sure that this tile really does overlap the search area
* (it could be just touching because of the expand-by-one in
* DBCellSrArea).
*/
if (!GEO_OVERLAP(&tileArea, &scx->scx_area)) return 0;
for (body = (CellTileBody *) TiGetBody(tile);
body != NULL;
body = body->ctb_next)
{
use = newScx.scx_use = body->ctb_use;
ASSERT(use != (CellUse *) NULL, "dbCellSrFunc");
/* The check below is to ensure that we only enumerate each
* cell once, even though it appears in many different tiles
* in the subcell plane.
*/
bbox = &use->cu_bbox;
if ( (tileArea.r_ybot <= bbox->r_ybot ||
(tileArea.r_ybot <= srchBot && bbox->r_ybot < srchBot))
&& (tileArea.r_xtop >= bbox->r_xtop ||
(tileArea.r_xtop >= srchRight && bbox->r_xtop >= srchRight)))
{
/* If not an array element, life is much simpler */
if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi)
{
newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi;
if (SigInterruptPending) return 1;
GEOINVERTTRANS(&use->cu_transform, &tinv);
GeoTransTrans(&use->cu_transform, &scx->scx_trans,
&newScx.scx_trans);
GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
if ((*fp->tf_func)(&newScx, fp->tf_arg) == 1)
return 1;
continue;
}
/*
* More than a single array element;
* check to see which ones overlap our search area.
*/
DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi);
xsep = (use->cu_xlo > use->cu_xhi) ? -use->cu_xsep : use->cu_xsep;
ysep = (use->cu_ylo > use->cu_yhi) ? -use->cu_ysep : use->cu_ysep;
for (newScx.scx_y = ylo; newScx.scx_y <= yhi; newScx.scx_y++)
for (newScx.scx_x = xlo; newScx.scx_x <= xhi; newScx.scx_x++)
{
if (SigInterruptPending) return 1;
xbase = xsep * (newScx.scx_x - use->cu_xlo);
ybase = ysep * (newScx.scx_y - use->cu_ylo);
GeoTransTranslate(xbase, ybase, &use->cu_transform, &t);
GEOINVERTTRANS(&t, &tinv);
GeoTransTrans(&t, &scx->scx_trans, &newScx.scx_trans);
GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
clientResult = (*fp->tf_func)(&newScx, fp->tf_arg);
if (clientResult == 2) goto skipArray;
else if (clientResult == 1) return 1;
}
}
skipArray: continue;
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* DBCellEnum --
*
* Apply the supplied procedure once to each CellUse in the subcell tile
* plane of the supplied CellDef. This procedure is not a geometric
* search, but rather a hierarchical enumeration.
*
* The procedure should be of the following form:
* int
* func(use, cdarg)
* CellUse *use;
* ClientData cdarg;
* {
* }
*
* Func returns 0 normally, 1 to abort the search.
*
* Results:
* 0 if search terminated normally, 1 if it aborted.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
DBCellEnum(cellDef, func, cdarg)
CellDef *cellDef; /* Def whose subcell plane is to be searched */
int (*func)(); /* Function to apply at every tile found */
ClientData cdarg; /* Argument to pass to function */
{
TreeFilter filter;
int dbEnumFunc();
filter.tf_func = func;
filter.tf_arg = cdarg;
if ((cellDef->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(cellDef, (char *) NULL, TRUE, NULL)) return 0;
if (TiSrArea((Tile *) NULL, cellDef->cd_planes[PL_CELL],
&TiPlaneRect, dbEnumFunc, (ClientData) &filter))
return 1;
else return 0;
}
/*
*-----------------------------------------------------------------------------
*
* dbEnumFunc --
*
* Filter procedure for DBCellEnum. Applies the procedure given
* to DBCellEnum to any of the CellUses in the tile that are
* enumerable.
*
* The scheme used for handling overlapping subcells is the same
* as used in DBCellSrArea above.
*
* Results:
* 0 normally, 1 if abort occurred.
*
* Side effects:
* Whatever side effects are brought about by applying the
* procedure supplied.
*
*-----------------------------------------------------------------------------
*/
int
dbEnumFunc(tile, fp)
Tile *tile;
TreeFilter *fp;
{
CellUse *use;
CellTileBody *body;
Rect *bbox;
for (body = (CellTileBody *) TiGetBody(tile);
body != NULL;
body = body->ctb_next)
{
use = body->ctb_use;
ASSERT(use != (CellUse *) NULL, "dbCellSrFunc");
bbox = &use->cu_bbox;
if ((BOTTOM(tile) <= bbox->r_ybot) && (RIGHT(tile) >= bbox->r_xtop))
if ((*fp->tf_func)(use, fp->tf_arg)) return 1;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBArraySr --
*
* Finds all elements of an array that fall in a particular area
* of the parent, and calls func for each element found.
*
* The procedure should be of the following form:
* int
* func(cellUse, trans, x, y, cdarg)
* CellUse *celluse;
* Transform *trans;
* int x, y;
* ClientData cdarg;
* {}
*
* In the above, cellUse is the original cellUse, trans is
* a transformation from the coordinates of the cell def to
* the coordinates of the use (for this array element), x and
* y are the indices of this array element, and cdarg is
* the ClientData supplied to us. If 1 is returned by func,
* it is a signal to abort the search.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* Whatever func does.
*
* ----------------------------------------------------------------------------
*/
int
DBArraySr(use, searchArea, func, cdarg)
CellUse *use; /* CellUse of array to be searched. */
Rect *searchArea; /* Area of interest, given in the
* coordinates of the parent (i.e. the
* cell use, not def). Must overlap
* the array bounding box.
*/
int (*func)(); /* Function to apply for each overlapping
* array element.
*/
ClientData cdarg; /* Client-specific info to give to func. */
{
int xlo, xhi, ylo, yhi, x, y;
int xsep, ysep, xbase, ybase;
Transform t;
DBArrayOverlap(use, searchArea, &xlo, &xhi, &ylo, &yhi);
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;
for (y = ylo; y <= yhi; y++)
for (x = xlo; x <= xhi; x++)
{
if (SigInterruptPending) return 1;
xbase = xsep * (x - use->cu_xlo);
ybase = ysep * (y - use->cu_ylo);
GeoTransTranslate(xbase, ybase, &use->cu_transform, &t);
if ((*func)(use, &t, x, y, cdarg)) return 1;
}
return 0;
}
/* Linked list structures for tile, celldef, and celluse enumeration */
typedef struct LT1 /* A linked tile record */
{
Tile *tile; /* Pointer to a tile */
struct LT1 *t_next; /* Pointer to another linked tile record */
} LinkedTile;
typedef struct LCD1 /* A linked celldef record */
{
CellDef *cellDef; /* Pointer to a celldef */
struct LCD1 *cd_next; /* Pointer to another linked celldef record */
} LinkedCellDef;
typedef struct LCU1 /* A linked celluse record */
{
CellUse *cellUse; /* Pointer to a celluse */
struct LCU1 *cu_next; /* Pointer to another linked celluse record */
} LinkedCellUse;
/*
* ----------------------------------------------------------------------------
*
* DBScaleValue ---
*
* Scale an integer by a factor of (scalen / scaled). Always round down.
* this requires correcting integer arithmetic for negative numbers on
* the division step. Values representing INFINITY are not scaled.
*
* Results:
* TRUE if the value does not scale exactly, FALSE otherwise.
*
* Side effects:
* Integer value passed as pointer is scaled, unless it represents
* an INFINITY measure.
*
* ----------------------------------------------------------------------------
*/
bool
DBScaleValue(v, n, d)
int *v, n, d;
{
dlong llv = (dlong)(*v);
if ((llv < (dlong)(INFINITY - 2)) && (llv > (dlong)(MINFINITY + 2)))
{
llv *= (dlong)n;
if (llv > 0)
llv /= (dlong)d;
else if (llv < 0)
llv = ((llv + 1) / (dlong)d) - 1;
*v = (int)llv;
/* Hopefully we do not reach this error. If we do, there's */
/* not much we can do about it except to increase Magic's */
/* internal Point structure to hold 8-byte integer values. */
if ((dlong)(*v) != llv)
TxError("ERROR: ARITHMETIC OVERFLOW in DBScaleValue()!\n");
}
return (((*v) % d) != 0);
}
/*
* ----------------------------------------------------------------------------
*
* DBScalePoint ---
*
* Scale a point by a factor of (scalen / scaled). Always round down.
* this requires correcting integer arithmetic for negative numbers on
* the division step.
*
* Results:
* TRUE if the point does not scale exactly, FALSE otherwise.
*
* Side effects:
* Point structure pointed to by the first argument is scaled.
*
* ----------------------------------------------------------------------------
*/
bool
DBScalePoint(p, n, d)
Point *p;
int n, d;
{
bool result;
result = DBScaleValue(&p->p_x, n, d);
result |= DBScaleValue(&p->p_y, n, d);
return result;
}
/*
* ----------------------------------------------------------------------------
*
* DBScaleEverything ---
*
* Scale all geometry by a factor of (scalen / scaled). This procedure
* cannot be undone!
*
* Results:
* None.
*
* Side Effects:
* Every single tile, label, and cell is altered.
* Geometry may be irrevocably distorted if transformed measurements
* would be sub-integer. The MODIFIED flag is set on any cell for
* which any internal geometry does not scale precisely.
*
* ----------------------------------------------------------------------------
*/
void
DBScaleEverything(scalen, scaled)
int scalen, scaled;
{
int dbCellDefEnumFunc();
LinkedCellDef *lhead, *lcd;
// DBUpdateStamps();
SigDisableInterrupts();
lhead = NULL;
(void) DBCellSrDefs(0, dbCellDefEnumFunc, (ClientData) &lhead);
/* Apply scaling function to each CellDef */
lcd = lhead;
while (lcd != NULL)
{
dbScaleCell(lcd->cellDef, scalen, scaled);
lcd = lcd->cd_next;
}
/* Free the linked CellDef list */
lcd = lhead;
while (lcd != NULL)
{
freeMagic((char *)lcd);
lcd = lcd->cd_next;
}
/* Recovery of global plane pointers */
MZAttachHintPlanes();
SigEnableInterrupts();
}
/* Structure needed to hold information about the plane to copy */
struct scaleArg {
int scalen;
int scaled;
int pnum;
Plane *ptarget;
bool doCIF;
bool modified;
};
/*
* ----------------------------------------------------------------------------
*
* dbScalePlane --
*
* Scaling procedure called on a single plane. Copies paint into the
* new plane at a scalefactor according to ratio (scalen / scaled)
*
* ----------------------------------------------------------------------------
*/
bool
dbScalePlane(oldplane, newplane, pnum, scalen, scaled, doCIF)
Plane *oldplane, *newplane;
int pnum;
int scalen, scaled;
bool doCIF;
{
int dbTileScaleFunc(); /* forward declaration */
struct scaleArg arg;
arg.scalen = scalen;
arg.scaled = scaled;
arg.ptarget = newplane;
arg.pnum = pnum;
arg.doCIF = doCIF;
arg.modified = FALSE;
(void) DBSrPaintArea((Tile *) NULL, oldplane, &TiPlaneRect,
&DBAllButSpaceBits, dbTileScaleFunc, (ClientData) &arg);
return arg.modified;
}
/*
* ----------------------------------------------------------------------------
*
* dbTileScaleFunc --
*
* Scaling procedure called on each tile being copied from one plane to
* another. Scaling ratio (scalen / scaled) is stored inside the struct
* scaleArg before calling.
*
* ----------------------------------------------------------------------------
*/
int
dbTileScaleFunc(tile, scvals)
Tile *tile;
struct scaleArg *scvals;
{
TileType type;
Rect targetRect;
TileType exact;
TiToRect(tile, &targetRect);
if (DBScalePoint(&targetRect.r_ll, scvals->scalen, scvals->scaled))
scvals->modified = TRUE;
if (DBScalePoint(&targetRect.r_ur, scvals->scalen, scvals->scaled))
scvals->modified = TRUE;
/* Tile scaled out of existence! */
if ((targetRect.r_xtop - targetRect.r_xbot == 0) ||
(targetRect.r_ytop - targetRect.r_ybot == 0))
{
TxPrintf("Tile 0x%x at (%d, %d) has zero area after scaling: Removed.\n",
tile, targetRect.r_xbot, targetRect.r_ybot);
return 0;
}
type = TiGetTypeExact(tile);
exact = type;
if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(scvals->ptarget, exact, &targetRect,
((scvals->doCIF) ? CIFPaintTable :
DBStdPaintTbl(type, scvals->pnum)),
(PaintUndoInfo *)NULL);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBSrCellUses --
*
* Do function "func" for each cell use in cellDef, passing "arg" as
* client data. Unlike DBEnumCell, this routine first collects a linked
* list of cell uses, then performs the function on the list, so that
* the search cannot be corrupted by, removing or reallocating the use
* structure from the cell def. Function "func" takes 2 arguments:
*
* int func(Celluse *use, ClientData arg) {}
*
* Results:
* 0 one successful completion of the search, 1 on error.
*
* Side Effects:
* Whatever "func" does.
*
* ----------------------------------------------------------------------------
*/
int
DBSrCellUses(cellDef, func, arg)
CellDef *cellDef; /* Pointer to CellDef to search for uses. */
int (*func)(); /* Function to apply for each cell use. */
ClientData arg; /* data to be passed to function func(). */
{
int dbCellUseEnumFunc();
int retval;
CellUse *use;
LinkedCellUse *luhead, *lu;
/* DBCellEnum() attempts to read unavailable celldefs. We don't */
/* want to do that here, so check CDAVAILABLE flag first. */
if ((cellDef->cd_flags & CDAVAILABLE) == 0) return 0;
/* Enumerate all unique cell uses, and scale their position, */
/* transform, and array information. */
luhead = NULL;
retval = DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
lu = luhead;
while (lu != NULL)
{
use = lu->cellUse;
if ((*func)(use, arg)) {
retval = 1;
break;
}
lu = lu->cu_next;
}
/* Free this linked cellUse structure */
lu = luhead;
while (lu != NULL)
{
freeMagic((char *)lu);
lu = lu->cu_next;
}
return retval;
}
/*
* ----------------------------------------------------------------------------
*
* dbScaleCell --
*
* Scaling procedure called on each cell encountered in the search.
*
* ----------------------------------------------------------------------------
*/
int
dbScaleCell(cellDef, scalen, scaled)
CellDef *cellDef; /* Pointer to CellDef to be saved. This def might
* be an internal buffer; if so, we ignore it.
*/
int scalen, scaled; /* scale numerator and denominator. */
{
int dbCellTileEnumFunc(), dbCellUseEnumFunc();
Label *lab;
int pNum;
LinkedTile *lhead, *lt;
LinkedCellUse *luhead, *lu;
Plane *newplane;
/* DBCellEnum() attempts to read unavailable celldefs. We don't */
/* want to do that here, so check CDAVAILABLE flag first. */
if ((cellDef->cd_flags & CDAVAILABLE) == 0)
goto donecell;
else
cellDef->cd_flags |= CDBOXESCHANGED;
/* Enumerate all unique cell uses, and scale their position, */
/* transform, and array information. */
luhead = NULL;
(void) DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
lu = luhead;
while (lu != NULL)
{
CellUse *use;
Rect *bbox;
use = lu->cellUse;
bbox = &use->cu_bbox;
/* TxPrintf("CellUse: BBox is ll (%d, %d), transform [%d %d %d %d %d %d]\n",
bbox->r_xbot, bbox->r_ybot,
use->cu_transform.t_a, use->cu_transform.t_b, use->cu_transform.t_c,
use->cu_transform.t_d, use->cu_transform.t_e, use->cu_transform.t_f); */
DBScalePoint(&bbox->r_ll, scalen, scaled);
DBScalePoint(&bbox->r_ur, scalen, scaled);
bbox = &use->cu_extended;
DBScalePoint(&bbox->r_ll, scalen, scaled);
DBScalePoint(&bbox->r_ur, scalen, scaled);
DBScaleValue(&use->cu_transform.t_c, scalen, scaled);
DBScaleValue(&use->cu_transform.t_f, scalen, scaled);
DBScaleValue(&use->cu_array.ar_xsep, scalen, scaled);
DBScaleValue(&use->cu_array.ar_ysep, scalen, scaled);
lu = lu->cu_next;
}
/* Free this linked cellUse structure */
lu = luhead;
while (lu != NULL)
{
freeMagic((char *)lu);
lu = lu->cu_next;
}
/* Scale the position of all subcell uses. Count all of the tiles in the */
/* subcell plane, and scale those without reference to the actual cells (so */
/* we don't count the cells multiple times). */
lhead = NULL;
(void) TiSrArea((Tile *)NULL, cellDef->cd_planes[PL_CELL], &TiPlaneRect,
dbCellTileEnumFunc, (ClientData) &lhead);
/* Scale each of the tiles in the linked list by (n / d) */
/* Don't scale (M)INFINITY on boundary tiles! */
lt = lhead;
while (lt != NULL)
{
DBScalePoint(&lt->tile->ti_ll, scalen, scaled);
lt = lt->t_next;
}
/* Free this linked tile structure */
lt = lhead;
while (lt != NULL)
{
freeMagic((char *)lt);
lt = lt->t_next;
}
/* Scale all of the paint tiles in this cell by creating a new plane */
/* and copying all tiles into the new plane at scaled dimensions. */
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
{
if (cellDef->cd_planes[pNum] == NULL) continue;
newplane = DBNewPlane((ClientData) TT_SPACE);
DBClearPaintPlane(newplane);
if (dbScalePlane(cellDef->cd_planes[pNum], newplane, pNum,
scalen, scaled, FALSE))
cellDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
DBFreePaintPlane(cellDef->cd_planes[pNum]);
TiFreePlane(cellDef->cd_planes[pNum]);
cellDef->cd_planes[pNum] = newplane;
}
/* Check consistency of several global pointers */
/* WARNING: This list may not be complete! */
/* Also scale the position of all labels. */
/* If labels are the rendered-font type, scale the size as well */
if (cellDef->cd_labels)
{
int i;
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
{
DBScalePoint(&lab->lab_rect.r_ll, scalen, scaled);
DBScalePoint(&lab->lab_rect.r_ur, scalen, scaled);
if (lab->lab_font >= 0)
{
DBScalePoint(&lab->lab_offset, scalen, scaled);
DBScaleValue(&lab->lab_size, scalen, scaled);
DBScalePoint(&lab->lab_bbox.r_ll, scalen, scaled);
DBScalePoint(&lab->lab_bbox.r_ur, scalen, scaled);
for (i = 0; i < 4; i++)
DBScalePoint(&lab->lab_corners[i], scalen, scaled);
}
}
}
donecell:
/* The cellDef bounding box gets expanded to match the new scale. */
DBScalePoint(&cellDef->cd_bbox.r_ll, scalen, scaled);
DBScalePoint(&cellDef->cd_bbox.r_ur, scalen, scaled);
DBScalePoint(&cellDef->cd_extended.r_ll, scalen, scaled);
DBScalePoint(&cellDef->cd_extended.r_ur, scalen, scaled);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* dbCellTileEnumFunc --
*
* Enumeration procedure called on each tile encountered in the search of
* the cell plane. Adds the tile to a linked list of tiles.
*
* ----------------------------------------------------------------------------
*/
int
dbCellTileEnumFunc(tile, arg)
Tile *tile;
LinkedTile **arg;
{
LinkedTile *lt;
lt = (LinkedTile *) mallocMagic(sizeof(LinkedTile));
lt->tile = tile;
lt->t_next = (*arg);
(*arg) = lt;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* dbCellDefEnumFunc --
*
* Enumeration procedure called on each CellDef encountered in the search of
* cells in the hierarchy. Adds the CellDef to a linked list of celldefs.
*
* ----------------------------------------------------------------------------
*/
int
dbCellDefEnumFunc(cellDef, arg)
CellDef *cellDef;
LinkedCellDef **arg;
{
LinkedCellDef *lcd;
lcd = (LinkedCellDef *) mallocMagic(sizeof(LinkedCellDef));
lcd->cellDef = cellDef;
lcd->cd_next = (*arg);
(*arg) = lcd;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* dbCellUseEnumFunc --
*
* Enumeration procedure called on each CellDef encountered in the search of
* cells in the hierarchy. Adds the CellDef to a linked list of celldefs.
*
* ----------------------------------------------------------------------------
*/
int
dbCellUseEnumFunc(cellUse, arg)
CellUse *cellUse;
LinkedCellUse **arg;
{
LinkedCellUse *lcu;
lcu = (LinkedCellUse *) mallocMagic(sizeof(LinkedCellUse));
lcu->cellUse = cellUse;
lcu->cu_next = (*arg);
(*arg) = lcu;
return 0;
}