blob: 72833439226ccecbf9a1b49936abda826d7c6e26 [file] [log] [blame]
/*@z15.c:Size Constraints:MinConstraint(), EnlargeToConstraint()@*************/
/* */
/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.24) */
/* COPYRIGHT (C) 1991, 2000 Jeffrey H. Kingston */
/* */
/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */
/* Basser Department of Computer Science */
/* The University of Sydney 2006 */
/* AUSTRALIA */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either Version 2, or (at your option) */
/* any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
/* */
/* FILE: z15.c */
/* MODULE: Size Constraints */
/* EXTERNS: MinConstraint(), EnlargeToConstraint(), */
/* ReflectConstraint(), SemiRotateConstraint(), */
/* RotateConstraint(), InvScaleConstraint(), Constrained(), */
/* EchoConstraint(), DebugConstrained() */
/* */
/*****************************************************************************/
#include <math.h>
#ifndef M_PI
#define M_PI 3.1415926535897931160E0
#endif
#include "externs.h"
/*****************************************************************************/
/* */
/* MinConstraint(xc, yc) */
/* */
/* Replace *xc by the minimum of the two constraints *xc and *yc. */
/* */
/*****************************************************************************/
void MinConstraint(CONSTRAINT *xc, CONSTRAINT *yc)
{ bc(*xc) = find_min(bc(*xc), bc(*yc));
bfc(*xc) = find_min(bfc(*xc), bfc(*yc));
fc(*xc) = find_min(fc(*xc), fc(*yc));
} /* end MinConstraint */
/*****************************************************************************/
/* */
/* SetSizeToMaxForwardConstraint(b, f, c) */
/* */
/* Set *b, *f to their largest possible value within constraint *c, such */
/* that *f is as large as possible. */
/* */
/*****************************************************************************/
void SetSizeToMaxForwardConstraint(FULL_LENGTH *b, FULL_LENGTH *f, CONSTRAINT *c)
{
*f = find_min(bfc(*c), fc(*c));
*b = find_min(bc(*c), bfc(*c) - *f);
} /* end EnlargeToConstraint */
/*****************************************************************************/
/* */
/* EnlargeToConstraint(b, f, c) */
/* */
/* Enlarge *b,*f to its largest possible value within constraint *c. */
/* */
/*****************************************************************************/
void EnlargeToConstraint(FULL_LENGTH *b, FULL_LENGTH *f, CONSTRAINT *c)
{
*f = find_min(bfc(*c) - *b, fc(*c));
} /* end EnlargeToConstraint */
/*****************************************************************************/
/* */
/* ReflectConstraint(xc, yc) */
/* */
/* Set xc to the constraint which is yc with its back and forward reversed. */
/* */
/*****************************************************************************/
#define ReflectConstraint(xc, yc) SetConstraint(xc, fc(yc), bfc(yc), bc(yc))
/*@::ScaleToConstraint(), InvScaleConstraint(), etc@**************************/
/* */
/* int ScaleToConstraint(b, f, c) */
/* */
/* Return the scale factor needed to scale object of size b, f down so it */
/* has a size which fits tightly into constraint c. */
/* */
/*****************************************************************************/
int ScaleToConstraint(FULL_LENGTH b, FULL_LENGTH f, CONSTRAINT *c)
{ float scale_factor; int res;
debug3(DSC, DD, "ScaleToConstraint(%s, %s, %s)", EchoLength(b),
EchoLength(f), EchoConstraint(c));
scale_factor = 1.0;
if( b > 0 ) scale_factor = find_min(scale_factor, (float) bc(*c)/b );
if( b + f > 0 ) scale_factor = find_min(scale_factor, (float) bfc(*c)/(b + f));
if( f > 0 ) scale_factor = find_min(scale_factor, (float) fc(*c)/f );
res = scale_factor * SF;
debug2(DSC, DD, "ScaleToConstraint returning %.2f (%d)", scale_factor, res);
return res;
} /* end ScaleToConstraint */
/*****************************************************************************/
/* */
/* InvScaleConstraint(yc, sf, xc) */
/* */
/* Scale constraint xc to the inverse of the scale factor sf. */
/* */
/*****************************************************************************/
void InvScaleConstraint(CONSTRAINT *yc, FULL_LENGTH sf, CONSTRAINT *xc)
{
#if DEBUG_ON
char buff[10];
#endif
ifdebug(DSC, DD, sprintf(buff, "%.3f", (float) sf / SF));
debug2(DSC, DD, "InvScaleConstraint(yc, %s, %s)", buff, EchoConstraint(xc));
assert( sf > 0, "InvScaleConstraint: sf <= 0!" );
bc(*yc) = bc(*xc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH :
find_min(MAX_FULL_LENGTH, bc(*xc) * SF / sf);
bfc(*yc) = bfc(*xc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH :
find_min(MAX_FULL_LENGTH, bfc(*xc)* SF / sf);
fc(*yc) = fc(*xc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH :
find_min(MAX_FULL_LENGTH, fc(*xc) * SF / sf);
debug1(DSC, DD, "InvScaleConstraint returning %s", EchoConstraint(yc));
} /* end InvScaleConstraint */
/*****************************************************************************/
/* */
/* static SemiRotateConstraint(xc, u, v, angle, yc) */
/* */
/* Used by RotateConstraint to calculate one rotated constraint. */
/* */
/*****************************************************************************/
static void SemiRotateConstraint(CONSTRAINT *xc, FULL_LENGTH u, FULL_LENGTH v,
float angle, CONSTRAINT *yc)
{ float cs, sn;
#if DEBUG_ON
char buff[20];
#endif
ifdebug(DSC, DD, sprintf(buff, "%.1f", angle * 360.0 / (2 * M_PI)));
debug4(DSC, DD, "SemiRotateConstraint(xc, %s, %s, %sd, %s",
EchoLength(u), EchoLength(v), buff, EchoConstraint(yc));
cs = cos(angle); sn = sin(angle);
if( fabs(cs) < 1e-6 )
SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
else
SetConstraint(*xc,
find_min(MAX_FULL_LENGTH, (bc(*yc) - u * sn) / cs),
find_min(MAX_FULL_LENGTH, (bfc(*yc) - u * sn - v * sn) / cs),
find_min(MAX_FULL_LENGTH, (fc(*yc) - v * sn) / cs ));
debug1(DSC, DD, "SemiRotateConstraint returning %s", EchoConstraint(xc));
} /* end SemiRotateConstraint */
/*@::RotateConstraint()@******************************************************/
/* */
/* RotateConstraint(c, y, angle, hc, vc, dim) */
/* */
/* Take the object angle @Rotate y, which is supposed to be constrained */
/* horizontally by hc and vertically by vc, and determine a constraint */
/* (either horizontal or vertical, depending on dim) for y. */
/* */
/* The constraint returned is a trigonometric function of all these */
/* parameters, including the present size of y in dimension 1-dim. */
/* */
/*****************************************************************************/
void RotateConstraint(CONSTRAINT *c, OBJECT y, FULL_LENGTH angle,
CONSTRAINT *hc, CONSTRAINT *vc, int dim)
{ CONSTRAINT c1, c2, c3, dc; float theta, psi;
#if DEBUG_ON
char buff[20];
#endif
ifdebug(DSC, DD, sprintf(buff, "%.1f", (float) angle / DG ));
debug4(DSC, DD, "RotateConstraint(c, y, %sd, %s, %s, %s)",
buff, EchoConstraint(hc), EchoConstraint(vc), dimen(dim));
/* work out angle in radians between 0 and 2*PI */
theta = (float) angle * 2 * M_PI / (float) (DG * 360);
while( theta < 0 ) theta += 2 * M_PI;
while( theta >= 2 * M_PI ) theta -= 2 * M_PI;
assert( 0 <= theta && theta <= 2 * M_PI, "RotateConstraint: theta!" );
/* determine theta, c1, and c2 depending on which quadrant we are in */
if( theta <= M_PI / 2.0 ) /* first quadrant */
{ theta = theta;
CopyConstraint(c1, *hc);
CopyConstraint(c2, *vc);
}
else if ( theta <= M_PI ) /* second quadrant */
{ theta -= M_PI / 2.0;
ReflectConstraint(c1, *vc);
CopyConstraint(c2, *hc);
}
else if ( theta <= 3.0 * M_PI / 2.0 ) /* third quadrant */
{ theta -= M_PI;
ReflectConstraint(c1, *hc);
ReflectConstraint(c2, *vc);
}
else /* fourth quadrant */
{ theta -= 3.0 * M_PI / 2.0;
CopyConstraint(c1, *vc);
ReflectConstraint(c2, *hc);
}
psi = M_PI / 2.0 - theta;
debug2(DSC, DD, " c1: %s; c2: %s", EchoConstraint(&c1), EchoConstraint(&c2));
/* return the minimum of the two constraints, rotated */
if( dim == COLM )
{ SemiRotateConstraint(c, back(y, ROWM), fwd(y, ROWM), theta, &c1);
ReflectConstraint(c3, c2);
SemiRotateConstraint(&dc, fwd(y, ROWM), back(y, ROWM), psi, &c3);
MinConstraint(c, &dc);
}
else
{ SemiRotateConstraint(c, back(y, COLM), fwd(y, COLM), psi, &c1);
SemiRotateConstraint(&dc, fwd(y, COLM), back(y, COLM), theta, &c2);
MinConstraint(c, &dc);
}
debug1(DSC, DD, "RotateConstraint returning %s", EchoConstraint(c));
} /* end RotateConstraint */
/*@::InsertScale()@***********************************************************/
/* */
/* BOOLEAN InsertScale(x, c) */
/* */
/* Insert a @Scale object above x so that x is scaled horizontally to fit */
/* constraint c. If this is not possible, owing to the necessary scale */
/* factor being too small, then don't do it; return FALSE instead. */
/* */
/*****************************************************************************/
BOOLEAN InsertScale(OBJECT x, CONSTRAINT *c)
{ int scale_factor; OBJECT prnt;
scale_factor = ScaleToConstraint(back(x, COLM), fwd(x, COLM), c);
if( scale_factor >= 0.2 * SF )
{
New(prnt, SCALE);
underline(prnt) = underline(x);
FposCopy(fpos(prnt), fpos(x));
/* set horizontal size and scale factor */
bc(constraint(prnt)) = scale_factor;
back(prnt, COLM) = ( back(x, COLM) * scale_factor ) / SF;
/* *** slightly too small?
fwd(prnt, COLM) = ( fwd(x, COLM) * scale_factor ) / SF;
*** */
fwd(prnt, COLM) = find_min(bfc(*c) - back(prnt, COLM), fc(*c));
/* set vertical size and scale factor */
fc(constraint(prnt)) = 1 * SF;
back(prnt, ROWM) = back(x, ROWM);
fwd(prnt, ROWM) = fwd(x, ROWM);
/* link prnt above x and return */
ReplaceNode(prnt, x);
Link(prnt, x);
return TRUE;
}
else return FALSE;
} /* end InsertScale */
/*@::CatConstrained()@********************************************************/
/* */
/* static CatConstrained(x, xc, ratm, y, dim, OBJECT *why) */
/* */
/* Calculate the size constraint of object x, as for Constrained below. */
/* y is the enclosing VCAT etc. object; ratm is TRUE if a ^ lies after */
/* x anywhere. dim is COLM or ROWM. */
/* */
/* The meaning of the key variables is as follows: */
/* */
/* be The amount by which back(x, dim) can increase from zero */
/* without having any impact on size(y, dim). Thereafter, */
/* any increase causes an equal increase in size(y, dim). */
/* */
/* fe The amount by which fwd(x, dim) can increase from zero */
/* without having any impact on size(y, dim). Thereafter, */
/* any increase causes an equal increase in size(y, dim). */
/* */
/* backy, The value that back(y, dim) and fwd(y, dim) would have if x */
/* fwdy was definite with size 0,0. They will in general be larger */
/* than the present values if x is indefinite, and smaller */
/* if x is definite, although it depends on marks and gaps. */
/* */
/*****************************************************************************/
static void CatConstrained(OBJECT x, CONSTRAINT *xc, BOOLEAN ratm,
OBJECT y, int dim, OBJECT *why)
{ int side; /* the size of y that x is on: BACK, ON, FWD */
CONSTRAINT yc; /* constraints on y */
FULL_LENGTH backy, fwdy; /* back(y), fwd(y) would be if x was (0, 0) */
FULL_LENGTH be, fe; /* amount back(x), fwd(x) can be for free */
FULL_LENGTH beffect, feffect; /* scratch variables for calculations */
FULL_LENGTH seffect; /* scratch variables for calculations */
OBJECT link, sg, pg; /* link to x, its successor and predecessor */
OBJECT prec_def, sd; /* definite object preceding (succeeding) x */
int tb, tbf, tf, tbc, tbfc, tfc, mxy, myz;
Constrained(y, &yc, dim, why);
if( constrained(yc) )
{
/* find the link of x, and its neighbours and their links */
link = UpDim(x, dim);
SetNeighbours(link, ratm, &pg, &prec_def, &sg, &sd, &side);
/* amount of space available at x without changing the size of y */
be = pg == nilobj ? 0 : ExtraGap(fwd(prec_def, dim), 0, &gap(pg), BACK);
fe = sg == nilobj ? 0 : ExtraGap(0, back(sd, dim), &gap(sg), FWD);
if( is_indefinite(type(x)) )
{
/* insert two lengths and delete one */
beffect = pg==nilobj ? 0 : MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
feffect = sg==nilobj ? 0 : MinGap(0, back(sd,dim), fwd(sd,dim), &gap(sg));
seffect = pg==nilobj ?
sg == nilobj ? 0 : back(sd, dim) :
sg == nilobj ? fwd(prec_def, dim) :
MinGap(fwd(prec_def, dim), back(sd, dim), fwd(sd, dim), &gap(sg));
switch( side )
{
case BACK: backy = back(y, dim) + beffect + feffect - seffect;
fwdy = fwd(y, dim);
break;
case ON: /* must be first, other cases prohibited */
backy = 0;
fwdy = fwd(y, dim) + feffect;
break;
case FWD: backy = back(y, dim);
fwdy = fwd(y, dim) + beffect + feffect - seffect;
break;
}
}
else /* x is definite */
{ beffect = pg == nilobj ? back(x, dim) :
MinGap(fwd(prec_def, dim), back(x,dim), fwd(x,dim), &gap(pg)) -
MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
feffect = sg == nilobj ? fwd(x, dim) :
MinGap(fwd(x, dim), back(sd, dim), fwd(sd, dim), &gap(sg)) -
MinGap(0, back(sd, dim), fwd(sd, dim), &gap(sg));
switch( side )
{
case BACK: backy = back(y, dim) - beffect - feffect;
fwdy = fwd(y, dim);
break;
case ON: backy = back(y, dim) - beffect;
fwdy = fwd(y, dim) - feffect;
break;
case FWD: backy = back(y, dim);
fwdy = fwd(y, dim) - beffect - feffect;
break;
}
}
debug5(DSC, DD, " side: %s, backy: %s, fwdy: %s, be: %s, fe: %s",
Image(side), EchoLength(backy), EchoLength(fwdy),
EchoLength(be), EchoLength(fe) );
if( !FitsConstraint(backy, fwdy, yc) )
SetConstraint(*xc, -1, -1, -1);
else switch( side )
{
case BACK:
tbc = bc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bc(yc) - backy;
tbfc = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - backy - fwdy;
mxy = find_min(tbc, tbfc);
tb = find_min(MAX_FULL_LENGTH, be + mxy);
tbf = find_min(MAX_FULL_LENGTH, be + fe + mxy);
tf = find_min(MAX_FULL_LENGTH, fe + mxy);
SetConstraint(*xc, tb, tbf, tf);
break;
case ON:
tbc = bc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bc(yc) - backy;
tbfc = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - backy - fwdy;
tfc = fc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : fc(yc) - fwdy;
mxy = find_min(tbc, tbfc);
myz = find_min(tfc, tbfc);
tb = find_min(MAX_FULL_LENGTH, be + mxy);
tbf = find_min(MAX_FULL_LENGTH, be + fe + tbfc);
tf = find_min(MAX_FULL_LENGTH, fe + myz);
SetConstraint(*xc, tb, tbf, tf);
break;
case FWD:
tfc = fc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : fc(yc) - fwdy;
tbfc = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - backy - fwdy;
mxy = find_min(tfc, tbfc);
tb = find_min(MAX_FULL_LENGTH, be + mxy);
tbf = find_min(MAX_FULL_LENGTH, be + fe + mxy);
tf = find_min(MAX_FULL_LENGTH, fe + mxy);
SetConstraint(*xc, tb, tbf, tf);
break;
}
} /* end if( constrained ) */
else SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
} /* end CatConstrained */
/*@::Constrained()@***********************************************************/
/* */
/* Constrained(x, xc, dim, why) */
/* */
/* Calculate the size constraint of object x, and return it in *xc. */
/* */
/* If the resulting constraint is a hard one caused by coming up against */
/* a HIGH (vertical) or WIDE (horizontal), set *why to this object; if */
/* not, leave *why unchanged. */
/* */
/*****************************************************************************/
void Constrained(OBJECT x, CONSTRAINT *xc, int dim, OBJECT *why)
{ OBJECT y, link, lp, rp, z, tlink, g; CONSTRAINT yc, hc, vc;
BOOLEAN ratm; FULL_LENGTH xback, xfwd; int tb, tf, tbf, tbc, tfc;
SetLengthDim(dim);
debug2(DSC, DD, "[ Constrained(%s, xc, %s, why), x =",
Image(type(x)), dimen(dim));
ifdebug(DSC, DD, DebugObject(x));
assert( Up(x) != x, "Constrained: x has no parent!" );
/* a CLOSURE which is external_ver is unconstrained in the ROWM direction */
/* a CLOSURE which is external_hor is unconstrained in both directions */
if( type(x) == CLOSURE && ((dim==ROWM && external_ver(x)) || external_hor(x)) )
{
SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
debug1(DSC, DD, "] Constrained returning %s (external)",EchoConstraint(xc));
return;
}
/* find y, the parent of x */
link = UpDim(x, dim); ratm = FALSE;
for( tlink = NextDown(link); type(tlink) == LINK; tlink = NextDown(tlink) )
{ Child(g, tlink);
if( type(g) == GAP_OBJ && mark(gap(g)) ) ratm = TRUE;
}
y = tlink;
debug1(DSC, DDD, "parent y = %s", Image(type(y)));
ifdebug(DSC, DDD, DebugObject(y));
switch( type(y) )
{
case PLAIN_GRAPHIC:
case GRAPHIC:
case LINK_SOURCE:
case LINK_DEST:
case KERN_SHRINK:
case BEGIN_HEADER:
case SET_HEADER:
case ONE_COL:
case ONE_ROW:
case HCONTRACT:
case VCONTRACT:
case HEXPAND:
case VEXPAND:
case START_HVSPAN:
case START_HSPAN:
case START_VSPAN:
case SPLIT:
case BACKGROUND:
Constrained(y, xc, dim, why);
break;
case HSCALE:
case VSCALE:
if( (dim == COLM) != (type(y) == HSCALE) ) Constrained(y, xc, dim, why);
else SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
break;
case HCOVER:
case VCOVER:
/* dubious, but not likely to arise anyway */
if( (dim == COLM) != (type(y) == HCOVER) ) Constrained(y, xc, dim, why);
else SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
break;
case SCALE:
Constrained(y, &yc, dim, why);
if( dim == COLM && bc(constraint(y)) == 0 )
{
/* Lout-supplied factor required later, could be tiny */
SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
}
else
{ InvScaleConstraint(xc,
dim == COLM ? bc(constraint(y)) : fc(constraint(y)), &yc);
}
break;
case ROTATE:
Constrained(y, &hc, COLM, why); Constrained(y, &vc, ROWM, why);
RotateConstraint(xc, x, sparec(constraint(y)), &hc, &vc, dim);
break;
case WIDE:
case HIGH:
Constrained(y, xc, dim, why);
if( (type(y)==WIDE) == (dim==COLM) )
{ MinConstraint(xc, &constraint(y));
*why = y;
}
break;
case HLIMITED:
case VLIMITED:
if( (type(y) == HLIMITED) == (dim == COLM) )
{
BOOLEAN still_searching = TRUE;
z = y;
SetConstraint(*xc, back(z, dim), size(z, dim), fwd(z, dim));
debug2(DSC, D, " [ %s (%s)", Image(type(z)), EchoConstraint(xc));
while( still_searching && Up(z) != z )
{
Parent(z, UpDim(z, dim));
switch( type(z) )
{
case VLIMITED:
case HLIMITED:
case COL_THR:
case ROW_THR:
case ONE_COL:
case ONE_ROW:
case HCONTRACT:
case VCONTRACT:
case SPLIT:
case START_VSPAN:
case START_HSPAN:
SetConstraint(*xc, back(z, dim), size(z, dim), fwd(z, dim));
debug2(DSC, DD, " let s = %s (%s)", Image(type(z)),
EchoConstraint(xc));
break;
case HSPANNER:
case VSPANNER:
/* SpannerAvailableSpace(z, dim, &b, &f); */
CopyConstraint(*xc, constraint(z));
debug2(DSC, D, " ] let s = %s (%s) and stop",
Image(type(z)), EchoConstraint(&constraint(z)));
still_searching = FALSE;
break;
default:
debug1(DSC, D, " ] stopping at %s", Image(type(z)));
still_searching = FALSE;
break;
}
}
*why = y;
}
else
{
Constrained(y, xc, dim, why);
}
break;
case VSPANNER:
case HSPANNER:
/* we're saying that a spanner has a fixed constraint that is */
/* determined just once in its life */
CopyConstraint(*xc, constraint(y));
debug2(DSC, DD, " Constrained(%s) = %s", Image(type(y)), EchoConstraint(xc));
/* SetConstraint(*xc, back(y, dim), size(y, dim), fwd(y, dim)); */
break;
case HSHIFT:
case VSHIFT:
if( (type(y) == HSHIFT) == (dim == COLM) )
{ Constrained(y, &yc, dim, why);
tf = FindShift(y, x, dim);
SetConstraint(*xc,
find_min(bc(yc), bfc(yc)) - tf, bfc(yc), find_min(fc(yc), bfc(yc)) + tf);
}
else Constrained(y, xc, dim, why);
break;
case HEAD:
if( dim == ROWM )
SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
else
{ CopyConstraint(yc, constraint(y));
debug1(DSC, DD, " head: %s; val is:", EchoConstraint(&yc));
ifdebug(DSC, DD, DebugObject(y));
goto REST_OF_HEAD; /* a few lines down */
}
break;
case COL_THR:
case ROW_THR:
assert( (type(y)==COL_THR) == (dim==COLM), "Constrained: COL_THR!" );
Constrained(y, &yc, dim, why);
tb = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - fwd(y, dim);
tb = find_min(bc(yc), tb);
tf = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - back(y, dim);
tf = find_min(fc(yc), tf);
SetConstraint(*xc, tb, bfc(yc), tf);
break;
case VCAT:
case HCAT:
case ACAT:
if( (type(y)==VCAT) == (dim==ROWM) )
{ CatConstrained(x, xc, ratm, y, dim, why);
break;
}
Constrained(y, &yc, dim, why);
if( !constrained(yc) )
SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
else
{
REST_OF_HEAD:
/* let lp and rp be the links of the gaps delimiting */
/* the components joined to x (or parent if no such) */
for( lp = PrevDown(link); lp != y; lp = PrevDown(lp) )
{ Child(z, lp);
if( type(z) == GAP_OBJ && !join(gap(z)) ) break;
}
for( rp = NextDown(link); rp != y; rp = NextDown(rp) )
{ Child(z, rp);
if( type(z) == GAP_OBJ && !join(gap(z)) ) break;
}
if( lp == y && rp == y && !(type(y) == HEAD && seen_nojoin(y)) )
{
/* if whole object is joined, do this */
tb = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - fwd(y, dim);
tb = find_min(bc(yc), tb);
tf = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - back(y, dim);
tf = find_min(fc(yc), tf);
SetConstraint(*xc, tb, bfc(yc), tf);
}
else
{
/* if // or || is present, do this */
xback = xfwd = 0;
for(link = NextDown(lp); link != rp; link = NextDown(link) )
{ Child(z, link);
if( type(z) == GAP_OBJ || is_index(type(z)) ) continue;
xback = find_max(xback, back(z, dim));
xfwd = find_max(xfwd, fwd(z, dim));
}
debug2(DSC, DD, " lp != rp; xback,xfwd = %s,%s",
EchoLength(xback), EchoLength(xfwd));
tbf = find_min(bfc(yc), fc(yc));
tbc = tbf == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : tbf - xfwd;
tfc = tbf == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : tbf - xback;
SetConstraint(*xc, tbc, tbf, tfc);
}
}
break;
default:
assert1(FALSE, "Constrained:", Image(type(y)));
break;
}
debug2(DSC, DD, "] Constrained %s returning %s", Image(type(x)),
EchoConstraint(xc));
} /* end Constrained */
/*@::EchoConstraint(), DebugConstrained()@************************************/
/* */
/* FULL_CHAR *EchoConstraint(c) */
/* */
/* Returns a string showing constraint *c, in centimetres. */
/* */
/*****************************************************************************/
#if DEBUG_ON
FULL_CHAR *EchoConstraint(CONSTRAINT *c)
{ static char str[2][40];
static int i = 0;
i = (i+1) % 2;
sprintf(str[i], "<%s, %s, %s>", EchoLength(bc(*c)), EchoLength(bfc(*c)),
EchoLength(fc(*c)));
return AsciiToFull(str[i]);
} /* end EchoConstraint */
/*****************************************************************************/
/* */
/* DebugConstrained(x) */
/* */
/* Calculate and print the constraints of all closures lying within */
/* sized object x. */
/* */
/*****************************************************************************/
void DebugConstrained(OBJECT x)
{ OBJECT y, link, why;
CONSTRAINT c;
debug1(DSC, DDD, "DebugConstrained( %s )", EchoObject(x) );
switch( type(x) )
{
case CROSS:
case FORCE_CROSS:
case ROTATE:
case BACKGROUND:
case INCGRAPHIC:
case SINCGRAPHIC:
case PLAIN_GRAPHIC:
case GRAPHIC:
case LINK_SOURCE:
case LINK_DEST:
case KERN_SHRINK:
case WORD:
case QWORD:
case START_HVSPAN:
case START_HSPAN:
case START_VSPAN:
case HSPAN:
case VSPAN:
break;
case CLOSURE:
Constrained(x, &c, COLM, &why);
debug2(DSC, DD, "Constrained( %s, &c, COLM ) = %s",
EchoObject(x), EchoConstraint(&c));
Constrained(x, &c, ROWM, &why);
debug2(DSC, DD, "Constrained( %s, &c, ROWM ) = %s",
EchoObject(x), EchoConstraint(&c));
break;
case SPLIT:
link = DownDim(x, COLM); Child(y, link);
DebugConstrained(y);
break;
case HEAD:
case ONE_COL:
case ONE_ROW:
case HCONTRACT:
case VCONTRACT:
case HLIMITED:
case VLIMITED:
case HEXPAND:
case VEXPAND:
case HSCALE:
case VSCALE:
case HCOVER:
case VCOVER:
case SCALE:
case WIDE:
case HIGH:
link = Down(x); Child(y, link);
DebugConstrained(y);
break;
case COL_THR:
case VCAT:
case HCAT:
case ACAT:
for( link = Down(x); link != x; link =NextDown(link) )
{ Child(y, link);
if( type(y) != GAP_OBJ && !is_index(type(y)) ) DebugConstrained(y);
}
break;
default:
assert1(FALSE, "DebugConstrained:", Image(type(x)));
break;
}
debug0(DSC, DDD, "DebugConstrained returning.");
} /* end DebugConstrained */
#endif