1 /*@z15.c:Size Constraints:MinConstraint(), EnlargeToConstraint()@*************/
2 /* */
3 /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39) */
4 /* COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston */
5 /* */
6 /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */
7 /* School of Information Technologies */
8 /* The University of Sydney 2006 */
9 /* AUSTRALIA */
10 /* */
11 /* This program is free software; you can redistribute it and/or modify */
12 /* it under the terms of the GNU General Public License as published by */
13 /* the Free Software Foundation; either Version 3, or (at your option) */
14 /* any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
24 /* */
25 /* FILE: z15.c */
26 /* MODULE: Size Constraints */
27 /* EXTERNS: MinConstraint(), EnlargeToConstraint(), */
28 /* ReflectConstraint(), SemiRotateConstraint(), */
29 /* RotateConstraint(), InvScaleConstraint(), Constrained(), */
30 /* EchoConstraint(), DebugConstrained() */
31 /* */
32 /*****************************************************************************/
33 #include <math.h>
34 #ifndef M_PI
35 #define M_PI 3.14159265358979323846
36 #endif
37 #include "externs.h"
38
39
40 /*****************************************************************************/
41 /* */
42 /* MinConstraint(xc, yc) */
43 /* */
44 /* Replace *xc by the minimum of the two constraints *xc and *yc. */
45 /* */
46 /*****************************************************************************/
47
MinConstraint(CONSTRAINT * xc,CONSTRAINT * yc)48 void MinConstraint(CONSTRAINT *xc, CONSTRAINT *yc)
49 { bc(*xc) = find_min(bc(*xc), bc(*yc));
50 bfc(*xc) = find_min(bfc(*xc), bfc(*yc));
51 fc(*xc) = find_min(fc(*xc), fc(*yc));
52 } /* end MinConstraint */
53
54
55 /*****************************************************************************/
56 /* */
57 /* SetSizeToMaxForwardConstraint(b, f, c) */
58 /* */
59 /* Set *b, *f to their largest possible value within constraint *c, such */
60 /* that *f is as large as possible. */
61 /* */
62 /*****************************************************************************/
63
SetSizeToMaxForwardConstraint(FULL_LENGTH * b,FULL_LENGTH * f,CONSTRAINT * c)64 void SetSizeToMaxForwardConstraint(FULL_LENGTH *b, FULL_LENGTH *f, CONSTRAINT *c)
65 {
66 *f = find_min(bfc(*c), fc(*c));
67 *b = find_min(bc(*c), bfc(*c) - *f);
68 } /* end EnlargeToConstraint */
69
70
71 /*****************************************************************************/
72 /* */
73 /* EnlargeToConstraint(b, f, c) */
74 /* */
75 /* Enlarge *b,*f to its largest possible value within constraint *c. */
76 /* */
77 /*****************************************************************************/
78
EnlargeToConstraint(FULL_LENGTH * b,FULL_LENGTH * f,CONSTRAINT * c)79 void EnlargeToConstraint(FULL_LENGTH *b, FULL_LENGTH *f, CONSTRAINT *c)
80 {
81 *f = find_min(bfc(*c) - *b, fc(*c));
82 } /* end EnlargeToConstraint */
83
84
85 /*****************************************************************************/
86 /* */
87 /* ReflectConstraint(xc, yc) */
88 /* */
89 /* Set xc to the constraint which is yc with its back and forward reversed. */
90 /* */
91 /*****************************************************************************/
92
93 #define ReflectConstraint(xc, yc) SetConstraint(xc, fc(yc), bfc(yc), bc(yc))
94
95
96 /*@::ScaleToConstraint(), InvScaleConstraint(), etc@**************************/
97 /* */
98 /* int ScaleToConstraint(b, f, c) */
99 /* */
100 /* Return the scale factor needed to scale object of size b, f down so it */
101 /* has a size which fits tightly into constraint c. */
102 /* */
103 /*****************************************************************************/
104
ScaleToConstraint(FULL_LENGTH b,FULL_LENGTH f,CONSTRAINT * c)105 int ScaleToConstraint(FULL_LENGTH b, FULL_LENGTH f, CONSTRAINT *c)
106 { float scale_factor; int res;
107 debug3(DSC, DD, "ScaleToConstraint(%s, %s, %s)", EchoLength(b),
108 EchoLength(f), EchoConstraint(c));
109 scale_factor = 1.0;
110 if( b > 0 ) scale_factor = find_min(scale_factor, (float) bc(*c)/b );
111 if( b + f > 0 ) scale_factor = find_min(scale_factor, (float) bfc(*c)/(b + f));
112 if( f > 0 ) scale_factor = find_min(scale_factor, (float) fc(*c)/f );
113 res = scale_factor * SF;
114 debug2(DSC, DD, "ScaleToConstraint returning %.2f (%d)", scale_factor, res);
115 return res;
116 } /* end ScaleToConstraint */
117
118
119 /*****************************************************************************/
120 /* */
121 /* InvScaleConstraint(yc, sf, xc) */
122 /* */
123 /* Scale constraint xc to the inverse of the scale factor sf. */
124 /* */
125 /*****************************************************************************/
126
InvScaleConstraint(CONSTRAINT * yc,FULL_LENGTH sf,CONSTRAINT * xc)127 void InvScaleConstraint(CONSTRAINT *yc, FULL_LENGTH sf, CONSTRAINT *xc)
128 {
129 #if DEBUG_ON
130 char buff[10];
131 #endif
132 ifdebug(DSC, DD, sprintf(buff, "%.3f", (float) sf / SF));
133 debug2(DSC, DD, "InvScaleConstraint(yc, %s, %s)", buff, EchoConstraint(xc));
134 assert( sf > 0, "InvScaleConstraint: sf <= 0!" );
135 bc(*yc) = bc(*xc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH :
136 find_min(MAX_FULL_LENGTH, bc(*xc) * SF / sf);
137 bfc(*yc) = bfc(*xc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH :
138 find_min(MAX_FULL_LENGTH, bfc(*xc)* SF / sf);
139 fc(*yc) = fc(*xc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH :
140 find_min(MAX_FULL_LENGTH, fc(*xc) * SF / sf);
141 debug1(DSC, DD, "InvScaleConstraint returning %s", EchoConstraint(yc));
142 } /* end InvScaleConstraint */
143
144
145 /*****************************************************************************/
146 /* */
147 /* static SemiRotateConstraint(xc, u, v, angle, yc) */
148 /* */
149 /* Used by RotateConstraint to calculate one rotated constraint. */
150 /* */
151 /*****************************************************************************/
152
SemiRotateConstraint(CONSTRAINT * xc,FULL_LENGTH u,FULL_LENGTH v,float angle,CONSTRAINT * yc)153 static void SemiRotateConstraint(CONSTRAINT *xc, FULL_LENGTH u, FULL_LENGTH v,
154 float angle, CONSTRAINT *yc)
155 { float cs, sn;
156 #if DEBUG_ON
157 char buff[20];
158 #endif
159 ifdebug(DSC, DD, sprintf(buff, "%.1f", angle * 360.0 / (2 * M_PI)));
160 debug4(DSC, DD, "SemiRotateConstraint(xc, %s, %s, %sd, %s",
161 EchoLength(u), EchoLength(v), buff, EchoConstraint(yc));
162 cs = cos(angle); sn = sin(angle);
163 if( fabs(cs) < 1e-6 )
164 SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
165 else
166 SetConstraint(*xc,
167 find_min(MAX_FULL_LENGTH, (bc(*yc) - u * sn) / cs),
168 find_min(MAX_FULL_LENGTH, (bfc(*yc) - u * sn - v * sn) / cs),
169 find_min(MAX_FULL_LENGTH, (fc(*yc) - v * sn) / cs ));
170 debug1(DSC, DD, "SemiRotateConstraint returning %s", EchoConstraint(xc));
171 } /* end SemiRotateConstraint */
172
173
174 /*@::RotateConstraint()@******************************************************/
175 /* */
176 /* RotateConstraint(c, y, angle, hc, vc, dim) */
177 /* */
178 /* Take the object angle @Rotate y, which is supposed to be constrained */
179 /* horizontally by hc and vertically by vc, and determine a constraint */
180 /* (either horizontal or vertical, depending on dim) for y. */
181 /* */
182 /* The constraint returned is a trigonometric function of all these */
183 /* parameters, including the present size of y in dimension 1-dim. */
184 /* */
185 /*****************************************************************************/
186
RotateConstraint(CONSTRAINT * c,OBJECT y,FULL_LENGTH angle,CONSTRAINT * hc,CONSTRAINT * vc,int dim)187 void RotateConstraint(CONSTRAINT *c, OBJECT y, FULL_LENGTH angle,
188 CONSTRAINT *hc, CONSTRAINT *vc, int dim)
189 { CONSTRAINT c1, c2, c3, dc; float theta, psi;
190 #if DEBUG_ON
191 char buff[20];
192 #endif
193 ifdebug(DSC, DD, sprintf(buff, "%.1f", (float) angle / DG ));
194 debug4(DSC, DD, "RotateConstraint(c, y, %sd, %s, %s, %s)",
195 buff, EchoConstraint(hc), EchoConstraint(vc), dimen(dim));
196
197 /* work out angle in radians between 0 and 2*M_PI */
198 theta = (float) angle * 2 * M_PI / (float) (DG * 360);
199 while( theta < 0 ) theta += 2 * M_PI;
200 while( theta >= 2 * M_PI ) theta -= 2 * M_PI;
201 assert( 0 <= theta && theta <= 2 * M_PI, "RotateConstraint: theta!" );
202
203 /* determine theta, c1, and c2 depending on which quadrant we are in */
204 if( theta <= M_PI / 2.0 ) /* first quadrant */
205 { theta = theta;
206 CopyConstraint(c1, *hc);
207 CopyConstraint(c2, *vc);
208 }
209 else if ( theta <= M_PI ) /* second quadrant */
210 { theta -= M_PI / 2.0;
211 ReflectConstraint(c1, *vc);
212 CopyConstraint(c2, *hc);
213 }
214 else if ( theta <= 3.0 * M_PI / 2.0 ) /* third quadrant */
215 { theta -= M_PI;
216 ReflectConstraint(c1, *hc);
217 ReflectConstraint(c2, *vc);
218 }
219 else /* fourth quadrant */
220 { theta -= 3.0 * M_PI / 2.0;
221 CopyConstraint(c1, *vc);
222 ReflectConstraint(c2, *hc);
223 }
224 psi = M_PI / 2.0 - theta;
225 debug2(DSC, DD, " c1: %s; c2: %s", EchoConstraint(&c1), EchoConstraint(&c2));
226
227 /* return the minimum of the two constraints, rotated */
228 if( dim == COLM )
229 { SemiRotateConstraint(c, back(y, ROWM), fwd(y, ROWM), theta, &c1);
230 ReflectConstraint(c3, c2);
231 SemiRotateConstraint(&dc, fwd(y, ROWM), back(y, ROWM), psi, &c3);
232 MinConstraint(c, &dc);
233 }
234 else
235 { SemiRotateConstraint(c, back(y, COLM), fwd(y, COLM), psi, &c1);
236 SemiRotateConstraint(&dc, fwd(y, COLM), back(y, COLM), theta, &c2);
237 MinConstraint(c, &dc);
238 }
239
240 debug1(DSC, DD, "RotateConstraint returning %s", EchoConstraint(c));
241 } /* end RotateConstraint */
242
243 /*@::InsertScale()@***********************************************************/
244 /* */
245 /* BOOLEAN InsertScale(x, c) */
246 /* */
247 /* Insert a @Scale object above x so that x is scaled horizontally to fit */
248 /* constraint c. If this is not possible, owing to the necessary scale */
249 /* factor being too small, then don't do it; return FALSE instead. */
250 /* */
251 /*****************************************************************************/
252
InsertScale(OBJECT x,CONSTRAINT * c)253 BOOLEAN InsertScale(OBJECT x, CONSTRAINT *c)
254 { int scale_factor; OBJECT prnt;
255 scale_factor = ScaleToConstraint(back(x, COLM), fwd(x, COLM), c);
256 if( scale_factor >= 0.2 * SF )
257 {
258 New(prnt, SCALE);
259 underline(prnt) = underline(x);
260 FposCopy(fpos(prnt), fpos(x));
261
262 /* set horizontal size and scale factor */
263 bc(constraint(prnt)) = scale_factor;
264 back(prnt, COLM) = ( back(x, COLM) * scale_factor ) / SF;
265
266 /* *** slightly too small?
267 fwd(prnt, COLM) = ( fwd(x, COLM) * scale_factor ) / SF;
268 *** */
269 fwd(prnt, COLM) = find_min(bfc(*c) - back(prnt, COLM), fc(*c));
270
271 /* set vertical size and scale factor */
272 fc(constraint(prnt)) = 1 * SF;
273 back(prnt, ROWM) = back(x, ROWM);
274 fwd(prnt, ROWM) = fwd(x, ROWM);
275
276 /* link prnt above x and return */
277 ReplaceNode(prnt, x);
278 Link(prnt, x);
279 return TRUE;
280 }
281 else return FALSE;
282 } /* end InsertScale */
283
284
285 /*@::CatConstrained()@********************************************************/
286 /* */
287 /* static CatConstrained(x, xc, ratm, y, dim, OBJECT *why) */
288 /* */
289 /* Calculate the size constraint of object x, as for Constrained below. */
290 /* y is the enclosing VCAT etc. object; ratm is TRUE if a ^ lies after */
291 /* x anywhere. dim is COLM or ROWM. */
292 /* */
293 /* The meaning of the key variables is as follows: */
294 /* */
295 /* be The amount by which back(x, dim) can increase from zero */
296 /* without having any impact on size(y, dim). Thereafter, */
297 /* any increase causes an equal increase in size(y, dim). */
298 /* */
299 /* fe The amount by which fwd(x, dim) can increase from zero */
300 /* without having any impact on size(y, dim). Thereafter, */
301 /* any increase causes an equal increase in size(y, dim). */
302 /* */
303 /* backy, The value that back(y, dim) and fwd(y, dim) would have if x */
304 /* fwdy was definite with size 0,0. They will in general be larger */
305 /* than the present values if x is indefinite, and smaller */
306 /* if x is definite, although it depends on marks and gaps. */
307 /* */
308 /*****************************************************************************/
309
CatConstrained(OBJECT x,CONSTRAINT * xc,BOOLEAN ratm,OBJECT y,int dim,OBJECT * why)310 static void CatConstrained(OBJECT x, CONSTRAINT *xc, BOOLEAN ratm,
311 OBJECT y, int dim, OBJECT *why)
312 { int side; /* the size of y that x is on: BACK, ON, FWD */
313 CONSTRAINT yc; /* constraints on y */
314 FULL_LENGTH backy=0, fwdy=0; /* back(y), fwd(y) would be if x was (0, 0) */
315 FULL_LENGTH be, fe; /* amount back(x), fwd(x) can be for free */
316 FULL_LENGTH beffect, feffect; /* scratch variables for calculations */
317 FULL_LENGTH seffect; /* scratch variables for calculations */
318 OBJECT link, sg, pg; /* link to x, its successor and predecessor */
319 OBJECT prec_def, sd; /* definite object preceding (succeeding) x */
320 int tb, tbf, tf, tbc, tbfc, tfc, mxy, myz;
321
322 Constrained(y, &yc, dim, why);
323 if( constrained(yc) )
324 {
325 /* find the link of x, and its neighbours and their links */
326 link = UpDim(x, dim);
327 SetNeighbours(link, ratm, &pg, &prec_def, &sg, &sd, &side);
328
329 /* amount of space available at x without changing the size of y */
330 be = pg == nilobj ? 0 : ExtraGap(fwd(prec_def, dim), 0, &gap(pg), BACK);
331 fe = sg == nilobj ? 0 : ExtraGap(0, back(sd, dim), &gap(sg), FWD);
332
333 if( is_indefinite(type(x)) )
334 {
335 /* insert two lengths and delete one */
336 beffect = pg==nilobj ? 0 : MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
337 feffect = sg==nilobj ? 0 : MinGap(0, back(sd,dim), fwd(sd,dim), &gap(sg));
338 seffect = pg==nilobj ?
339 sg == nilobj ? 0 : back(sd, dim) :
340 sg == nilobj ? fwd(prec_def, dim) :
341 MinGap(fwd(prec_def, dim), back(sd, dim), fwd(sd, dim), &gap(sg));
342
343 switch( side )
344 {
345 case BACK: backy = back(y, dim) + beffect + feffect - seffect;
346 fwdy = fwd(y, dim);
347 break;
348
349 case ON: /* must be first, other cases prohibited */
350 backy = 0;
351 fwdy = fwd(y, dim) + feffect;
352 break;
353
354 case FWD: backy = back(y, dim);
355 fwdy = fwd(y, dim) + beffect + feffect - seffect;
356 break;
357 }
358 }
359
360 else /* x is definite */
361
362 { beffect = pg == nilobj ? back(x, dim) :
363 MinGap(fwd(prec_def, dim), back(x,dim), fwd(x,dim), &gap(pg)) -
364 MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
365
366 feffect = sg == nilobj ? fwd(x, dim) :
367 MinGap(fwd(x, dim), back(sd, dim), fwd(sd, dim), &gap(sg)) -
368 MinGap(0, back(sd, dim), fwd(sd, dim), &gap(sg));
369
370 switch( side )
371 {
372 case BACK: backy = back(y, dim) - beffect - feffect;
373 fwdy = fwd(y, dim);
374 break;
375
376 case ON: backy = back(y, dim) - beffect;
377 fwdy = fwd(y, dim) - feffect;
378 break;
379
380 case FWD: backy = back(y, dim);
381 fwdy = fwd(y, dim) - beffect - feffect;
382 break;
383 }
384 }
385
386 debug5(DSC, DD, " side: %s, backy: %s, fwdy: %s, be: %s, fe: %s",
387 Image(side), EchoLength(backy), EchoLength(fwdy),
388 EchoLength(be), EchoLength(fe) );
389
390 if( !FitsConstraint(backy, fwdy, yc) )
391 SetConstraint(*xc, -1, -1, -1);
392 else switch( side )
393 {
394
395 case BACK:
396
397 tbc = bc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bc(yc) - backy;
398 tbfc = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - backy - fwdy;
399 mxy = find_min(tbc, tbfc);
400 tb = find_min(MAX_FULL_LENGTH, be + mxy);
401 tbf = find_min(MAX_FULL_LENGTH, be + fe + mxy);
402 tf = find_min(MAX_FULL_LENGTH, fe + mxy);
403 SetConstraint(*xc, tb, tbf, tf);
404 break;
405
406
407 case ON:
408
409 tbc = bc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bc(yc) - backy;
410 tbfc = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - backy - fwdy;
411 tfc = fc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : fc(yc) - fwdy;
412 mxy = find_min(tbc, tbfc);
413 myz = find_min(tfc, tbfc);
414 tb = find_min(MAX_FULL_LENGTH, be + mxy);
415 tbf = find_min(MAX_FULL_LENGTH, be + fe + tbfc);
416 tf = find_min(MAX_FULL_LENGTH, fe + myz);
417 SetConstraint(*xc, tb, tbf, tf);
418 break;
419
420
421 case FWD:
422
423 tfc = fc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : fc(yc) - fwdy;
424 tbfc = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - backy - fwdy;
425 mxy = find_min(tfc, tbfc);
426 tb = find_min(MAX_FULL_LENGTH, be + mxy);
427 tbf = find_min(MAX_FULL_LENGTH, be + fe + mxy);
428 tf = find_min(MAX_FULL_LENGTH, fe + mxy);
429 SetConstraint(*xc, tb, tbf, tf);
430 break;
431
432 }
433 } /* end if( constrained ) */
434 else SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
435 } /* end CatConstrained */
436
437
438 /*@::Constrained()@***********************************************************/
439 /* */
440 /* Constrained(x, xc, dim, why) */
441 /* */
442 /* Calculate the size constraint of object x, and return it in *xc. */
443 /* */
444 /* If the resulting constraint is a hard one caused by coming up against */
445 /* a HIGH (vertical) or WIDE (horizontal), set *why to this object; if */
446 /* not, leave *why unchanged. */
447 /* */
448 /*****************************************************************************/
449
Constrained(OBJECT x,CONSTRAINT * xc,int dim,OBJECT * why)450 void Constrained(OBJECT x, CONSTRAINT *xc, int dim, OBJECT *why)
451 { OBJECT y, link, lp, rp, z, tlink, g; CONSTRAINT yc, hc, vc;
452 BOOLEAN ratm; FULL_LENGTH xback, xfwd; int tb, tf, tbf, tbc, tfc;
453 SetLengthDim(dim);
454 debug2(DSC, DD, "[ Constrained(%s, xc, %s, why), x =",
455 Image(type(x)), dimen(dim));
456 ifdebug(DSC, DD, DebugObject(x));
457 assert( Up(x) != x, "Constrained: x has no parent!" );
458
459 /* a CLOSURE which is external_ver is unconstrained in the ROWM direction */
460 /* a CLOSURE which is external_hor is unconstrained in both directions */
461 if( type(x) == CLOSURE && ((dim==ROWM && external_ver(x)) || external_hor(x)) )
462 {
463 SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
464 debug1(DSC, DD, "] Constrained returning %s (external)",EchoConstraint(xc));
465 return;
466 }
467
468 /* find y, the parent of x */
469 link = UpDim(x, dim); ratm = FALSE;
470 for( tlink = NextDown(link); type(tlink) == LINK; tlink = NextDown(tlink) )
471 { Child(g, tlink);
472 if( type(g) == GAP_OBJ && mark(gap(g)) ) ratm = TRUE;
473 }
474 y = tlink;
475 debug1(DSC, DDD, "parent y = %s", Image(type(y)));
476 ifdebug(DSC, DDD, DebugObject(y));
477
478 switch( type(y) )
479 {
480 case PLAIN_GRAPHIC:
481 case GRAPHIC:
482 case LINK_SOURCE:
483 case LINK_DEST:
484 case LINK_DEST_NULL:
485 case LINK_URL:
486 case KERN_SHRINK:
487 case BEGIN_HEADER:
488 case SET_HEADER:
489 case ONE_COL:
490 case ONE_ROW:
491 case HCONTRACT:
492 case VCONTRACT:
493 case HEXPAND:
494 case VEXPAND:
495 case START_HVSPAN:
496 case START_HSPAN:
497 case START_VSPAN:
498 case SPLIT:
499 case BACKGROUND:
500
501 Constrained(y, xc, dim, why);
502 break;
503
504
505 case HMIRROR:
506 case VMIRROR:
507
508 if( (dim == COLM) == (type(y) == HMIRROR) )
509 {
510 Constrained(y, &yc, dim, why);
511 FlipConstraint(*xc, yc);
512 }
513 else
514 Constrained(y, xc, dim, why);
515 break;
516
517
518 case HSCALE:
519 case VSCALE:
520
521 if( (dim == COLM) != (type(y) == HSCALE) ) Constrained(y, xc, dim, why);
522 else SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
523 break;
524
525
526 case HCOVER:
527 case VCOVER:
528
529 /* dubious, but not likely to arise anyway */
530 if( (dim == COLM) != (type(y) == HCOVER) ) Constrained(y, xc, dim, why);
531 else SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
532 break;
533
534
535 case SCALE:
536
537 Constrained(y, &yc, dim, why);
538 if( dim == COLM && bc(constraint(y)) == 0 )
539 {
540 /* Lout-supplied factor required later, could be tiny */
541 SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
542 }
543 else
544 { InvScaleConstraint(xc,
545 dim == COLM ? bc(constraint(y)) : fc(constraint(y)), &yc);
546 }
547 break;
548
549
550 case ROTATE:
551
552 Constrained(y, &hc, COLM, why); Constrained(y, &vc, ROWM, why);
553 RotateConstraint(xc, x, sparec(constraint(y)), &hc, &vc, dim);
554 break;
555
556
557 case WIDE:
558 case HIGH:
559
560 Constrained(y, xc, dim, why);
561 if( (type(y)==WIDE) == (dim==COLM) )
562 { MinConstraint(xc, &constraint(y));
563 *why = y;
564 }
565 break;
566
567
568 case HLIMITED:
569 case VLIMITED:
570
571 if( (type(y) == HLIMITED) == (dim == COLM) )
572 {
573 BOOLEAN still_searching = TRUE;
574 z = y;
575 SetConstraint(*xc, back(z, dim), size(z, dim), fwd(z, dim));
576 debug2(DSC, D, " [ %s (%s)", Image(type(z)), EchoConstraint(xc));
577 while( still_searching && Up(z) != z )
578 {
579 Parent(z, UpDim(z, dim));
580 switch( type(z) )
581 {
582 case VLIMITED:
583 case HLIMITED:
584 case COL_THR:
585 case ROW_THR:
586 case ONE_COL:
587 case ONE_ROW:
588 case HCONTRACT:
589 case VCONTRACT:
590 case SPLIT:
591 case START_VSPAN:
592 case START_HSPAN:
593
594 SetConstraint(*xc, back(z, dim), size(z, dim), fwd(z, dim));
595 debug2(DSC, DD, " let s = %s (%s)", Image(type(z)),
596 EchoConstraint(xc));
597 break;
598
599
600 case HSPANNER:
601 case VSPANNER:
602
603 /* SpannerAvailableSpace(z, dim, &b, &f); */
604 CopyConstraint(*xc, constraint(z));
605 debug2(DSC, D, " ] let s = %s (%s) and stop",
606 Image(type(z)), EchoConstraint(&constraint(z)));
607 still_searching = FALSE;
608 break;
609
610
611 default:
612
613 debug1(DSC, D, " ] stopping at %s", Image(type(z)));
614 still_searching = FALSE;
615 break;
616 }
617 }
618 *why = y;
619 }
620 else
621 {
622 Constrained(y, xc, dim, why);
623 }
624 break;
625
626
627 case VSPANNER:
628 case HSPANNER:
629
630 /* we're saying that a spanner has a fixed constraint that is */
631 /* determined just once in its life */
632 CopyConstraint(*xc, constraint(y));
633 debug2(DSC, DD, " Constrained(%s) = %s", Image(type(y)), EchoConstraint(xc));
634 /* SetConstraint(*xc, back(y, dim), size(y, dim), fwd(y, dim)); */
635 break;
636
637
638 case HSHIFT:
639 case VSHIFT:
640
641 if( (type(y) == HSHIFT) == (dim == COLM) )
642 { Constrained(y, &yc, dim, why);
643 tf = FindShift(y, x, dim);
644 SetConstraint(*xc,
645 find_min(bc(yc), bfc(yc)) - tf, bfc(yc), find_min(fc(yc), bfc(yc)) + tf);
646 }
647 else Constrained(y, xc, dim, why);
648 break;
649
650
651 case HEAD:
652
653 if( dim == ROWM )
654 SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
655 else
656 { CopyConstraint(yc, constraint(y));
657 debug1(DSC, DD, " head: %s; val is:", EchoConstraint(&yc));
658 ifdebug(DSC, DD, DebugObject(y));
659 goto REST_OF_HEAD; /* a few lines down */
660 }
661 break;
662
663
664 case COL_THR:
665 case ROW_THR:
666
667 assert( (type(y)==COL_THR) == (dim==COLM), "Constrained: COL_THR!" );
668 Constrained(y, &yc, dim, why);
669 tb = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - fwd(y, dim);
670 tb = find_min(bc(yc), tb);
671 tf = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - back(y, dim);
672 tf = find_min(fc(yc), tf);
673 SetConstraint(*xc, tb, bfc(yc), tf);
674 break;
675
676
677 case VCAT:
678 case HCAT:
679 case ACAT:
680
681 if( (type(y)==VCAT) == (dim==ROWM) )
682 { CatConstrained(x, xc, ratm, y, dim, why);
683 break;
684 }
685 Constrained(y, &yc, dim, why);
686 if( !constrained(yc) )
687 SetConstraint(*xc, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
688 else
689 {
690 REST_OF_HEAD:
691 /* let lp and rp be the links of the gaps delimiting */
692 /* the components joined to x (or parent if no such) */
693 for( lp = PrevDown(link); lp != y; lp = PrevDown(lp) )
694 { Child(z, lp);
695 if( type(z) == GAP_OBJ && !join(gap(z)) ) break;
696 }
697 for( rp = NextDown(link); rp != y; rp = NextDown(rp) )
698 { Child(z, rp);
699 if( type(z) == GAP_OBJ && !join(gap(z)) ) break;
700 }
701 if( lp == y && rp == y && !(type(y) == HEAD && seen_nojoin(y)) )
702 {
703 /* if whole object is joined, do this */
704 tb = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - fwd(y, dim);
705 tb = find_min(bc(yc), tb);
706 tf = bfc(yc) == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : bfc(yc) - back(y, dim);
707 tf = find_min(fc(yc), tf);
708 SetConstraint(*xc, tb, bfc(yc), tf);
709 }
710 else
711 {
712 /* if // or || is present, do this */
713 xback = xfwd = 0;
714 for(link = NextDown(lp); link != rp; link = NextDown(link) )
715 { Child(z, link);
716 if( type(z) == GAP_OBJ || is_index(type(z)) ) continue;
717 xback = find_max(xback, back(z, dim));
718 xfwd = find_max(xfwd, fwd(z, dim));
719 }
720 debug2(DSC, DD, " lp != rp; xback,xfwd = %s,%s",
721 EchoLength(xback), EchoLength(xfwd));
722 tbf = find_min(bfc(yc), fc(yc));
723 tbc = tbf == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : tbf - xfwd;
724 tfc = tbf == MAX_FULL_LENGTH ? MAX_FULL_LENGTH : tbf - xback;
725 SetConstraint(*xc, tbc, tbf, tfc);
726 }
727 }
728 break;
729
730
731 default:
732
733 assert1(FALSE, "Constrained:", Image(type(y)));
734 break;
735
736 }
737 debug2(DSC, DD, "] Constrained %s returning %s", Image(type(x)),
738 EchoConstraint(xc));
739 } /* end Constrained */
740
741
742 /*@::EchoConstraint(), DebugConstrained()@************************************/
743 /* */
744 /* FULL_CHAR *EchoConstraint(c) */
745 /* */
746 /* Returns a string showing constraint *c, in centimetres. */
747 /* */
748 /*****************************************************************************/
749 #if DEBUG_ON
750
EchoConstraint(CONSTRAINT * c)751 FULL_CHAR *EchoConstraint(CONSTRAINT *c)
752 { static char str[2][40];
753 static int i = 0;
754 i = (i+1) % 2;
755 sprintf(str[i], "<%s, %s, %s>", EchoLength(bc(*c)), EchoLength(bfc(*c)),
756 EchoLength(fc(*c)));
757 return AsciiToFull(str[i]);
758 } /* end EchoConstraint */
759
760
761 /*****************************************************************************/
762 /* */
763 /* DebugConstrained(x) */
764 /* */
765 /* Calculate and print the constraints of all closures lying within */
766 /* sized object x. */
767 /* */
768 /*****************************************************************************/
769
DebugConstrained(OBJECT x)770 void DebugConstrained(OBJECT x)
771 { OBJECT y, link, why;
772 CONSTRAINT c;
773 debug1(DSC, DDD, "DebugConstrained( %s )", EchoObject(x) );
774 switch( type(x) )
775 {
776
777 case CROSS:
778 case FORCE_CROSS:
779 case ROTATE:
780 case BACKGROUND:
781 case INCGRAPHIC:
782 case SINCGRAPHIC:
783 case PLAIN_GRAPHIC:
784 case GRAPHIC:
785 case LINK_SOURCE:
786 case LINK_DEST:
787 case LINK_DEST_NULL:
788 case LINK_URL:
789 case KERN_SHRINK:
790 case WORD:
791 case QWORD:
792 case START_HVSPAN:
793 case START_HSPAN:
794 case START_VSPAN:
795 case HSPAN:
796 case VSPAN:
797
798 break;
799
800
801 case CLOSURE:
802
803 Constrained(x, &c, COLM, &why);
804 debug2(DSC, DD, "Constrained( %s, &c, COLM ) = %s",
805 EchoObject(x), EchoConstraint(&c));
806 Constrained(x, &c, ROWM, &why);
807 debug2(DSC, DD, "Constrained( %s, &c, ROWM ) = %s",
808 EchoObject(x), EchoConstraint(&c));
809 break;
810
811
812 case SPLIT:
813
814 link = DownDim(x, COLM); Child(y, link);
815 DebugConstrained(y);
816 break;
817
818
819 case HEAD:
820 case ONE_COL:
821 case ONE_ROW:
822 case HCONTRACT:
823 case VCONTRACT:
824 case HLIMITED:
825 case VLIMITED:
826 case HEXPAND:
827 case VEXPAND:
828 case HMIRROR:
829 case VMIRROR:
830 case HSCALE:
831 case VSCALE:
832 case HCOVER:
833 case VCOVER:
834 case SCALE:
835 case WIDE:
836 case HIGH:
837
838 link = Down(x); Child(y, link);
839 DebugConstrained(y);
840 break;
841
842
843 case COL_THR:
844 case VCAT:
845 case HCAT:
846 case ACAT:
847
848 for( link = Down(x); link != x; link =NextDown(link) )
849 { Child(y, link);
850 if( type(y) != GAP_OBJ && !is_index(type(y)) ) DebugConstrained(y);
851 }
852 break;
853
854
855 default:
856
857 assert1(FALSE, "DebugConstrained:", Image(type(x)));
858 break;
859
860 }
861 debug0(DSC, DDD, "DebugConstrained returning.");
862 } /* end DebugConstrained */
863 #endif
864