1 /*@z19.c:Galley Attaching:DetachGalley()@*************************************/
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: z19.c */
26 /* MODULE: Galley Attaching */
27 /* EXTERNS: SearchGalley(), AttachGalley(), DetachGalley() */
28 /* */
29 /*****************************************************************************/
30 #include "externs.h"
31
32
33 /*****************************************************************************/
34 /* */
35 /* OBJECT InterposeScale(y, scale_factor, dim) */
36 /* */
37 /* Interpose a @Scale symbol above y with the given scale factor. */
38 /* */
39 /*****************************************************************************/
40
InterposeScale(OBJECT y,int scale_factor,int dim)41 static OBJECT InterposeScale(OBJECT y, int scale_factor, int dim)
42 { OBJECT res;
43 New(res, SCALE);
44 FposCopy(fpos(res), fpos(y));
45 if( dim == COLM )
46 { bc(constraint(res)) = scale_factor;
47 fc(constraint(res)) = 1 * SF;
48 }
49 else
50 { bc(constraint(res)) = 1 * SF;
51 fc(constraint(res)) = scale_factor;
52 }
53 back(res, dim) = (back(y, dim) * scale_factor) / SF;
54 fwd(res, dim) = (fwd(y, dim) * scale_factor) / SF;
55 back(res, 1-dim) = back(y, 1-dim);
56 fwd(res, 1-dim) = fwd(y, 1-dim);
57 ReplaceNode(res, y);
58 Link(res, y);
59 return res;
60 } /* end InterposeScale */
61
62
63 /*****************************************************************************/
64 /* */
65 /* OBJECT InterposeWideOrHigh(y, dim) */
66 /* */
67 /* Interpose a @Wide or @High symbol above y with the same size as y, with */
68 /* a value which prevents any further increase in the size of y. */
69 /* */
70 /*****************************************************************************/
71
InterposeWideOrHigh(OBJECT y,int dim)72 static OBJECT InterposeWideOrHigh(OBJECT y, int dim)
73 { OBJECT res;
74 New(res, dim == COLM ? WIDE : HIGH);
75 FposCopy(fpos(res), fpos(y));
76 back(res, dim) = back(y, dim);
77 fwd(res, dim) = fwd(y, dim);
78 back(res, 1-dim) = back(y, 1-dim);
79 fwd(res, 1-dim) = fwd(y, 1-dim);
80 SetConstraint(constraint(res), MAX_FULL_LENGTH, size(res, dim), MAX_FULL_LENGTH);
81 ReplaceNode(res, y);
82 Link(res, y);
83 return res;
84 } /* end InterposeWideOrHigh */
85
86
87 /*****************************************************************************/
88 /* */
89 /* DetachGalley(hd) */
90 /* */
91 /* Detach galley hd from its target. */
92 /* */
93 /*****************************************************************************/
94
DetachGalley(OBJECT hd)95 void DetachGalley(OBJECT hd)
96 { OBJECT prnt, index;
97 assert( type(hd) == HEAD && Up(hd) != hd, "DetachGalley: precondition!" );
98 debug1(DGA, D, "DetachGalley( %s )", SymName(actual(hd)));
99 Parent(prnt, Up(hd));
100 assert( Up(prnt) != prnt, "DetachGalley: parent!" );
101 New(index, UNATTACHED);
102 actual(index) = nilobj;
103 non_blocking(index) = TRUE;
104 blocked(index) = FALSE;
105 pinpoint(index) = nilobj;
106 MoveLink(Up(hd), index, PARENT);
107 Link(NextDown(Up(prnt)), index);
108 debug0(DGA, D, "DetachGalley returning.");
109 } /* end DetachGalley */
110
111
112 /*@::SearchGalley()@**********************************************************/
113 /* */
114 /* OBJECT SearchGalley(start, sym, forwards, subgalleys, closures, input) */
115 /* */
116 /* Search a galley and its sub-galleys for a target which uses sym. The */
117 /* meanings of the flags are as follows: */
118 /* */
119 /* forwards If TRUE, search forwards from just after start, else */
120 /* search backwards from just before start */
121 /* subgalleys If TRUE, search down into sub-galleys of this galley */
122 /* closures If TRUE, closures in this galley are acceptable results */
123 /* input If TRUE, InputSym is an acceptable result */
124 /* */
125 /*****************************************************************************/
126
SearchGalley(OBJECT start,OBJECT sym,BOOLEAN forwards,BOOLEAN subgalleys,BOOLEAN closures,BOOLEAN input)127 OBJECT SearchGalley(OBJECT start, OBJECT sym, BOOLEAN forwards,
128 BOOLEAN subgalleys, BOOLEAN closures, BOOLEAN input)
129 { OBJECT y, res, z, zlink, link;
130 ifdebug(DGA, D, Parent(y, start));
131 debug6(DGA, D, "[ SearchGalley(%s, %s, %s, %s, %s, %s)",
132 type(start) == HEAD ? (char *) SymName(actual(start)) :
133 type(y) == HEAD ? (char *) SymName(actual(y)) : "link",
134 SymName(sym),
135 forwards ? "fwd" : "back", subgalleys ? "subgalleys" : "nosubgalleys",
136 closures ? "closures" : "noclosures", input ? "input" : "noinput");
137 assert( type(start) == LINK || type(start) == HEAD, "SearchGalley: start!" );
138
139 link = forwards ? NextDown(start) : PrevDown(start);
140 res = nilobj;
141 while( res == nilobj && type(link) != HEAD )
142 { Child(y, link);
143 switch( type(y) )
144 {
145 case UNATTACHED:
146 case RECEIVING:
147
148 debug1(DGA, D, " examining %s", EchoIndex(y));
149 if( subgalleys )
150 for( zlink = Down(y); zlink!=y && res==nilobj; zlink=NextDown(zlink) )
151 { Child(z, zlink);
152 res = SearchGalley(z, sym, TRUE, TRUE, TRUE, input);
153 }
154 if( res == nilobj && input && type(y) == RECEIVING &&
155 actual(actual(y)) == InputSym )
156 res = y;
157 break;
158
159
160 case RECEPTIVE:
161
162 debug1(DGA, D, " examining %s", EchoIndex(y));
163 if( closures && type(actual(y)) == CLOSURE
164 && SearchUses(actual(actual(y)), sym) ) res = y;
165 else if( input && actual(actual(y)) == InputSym ) res = y;
166 break;
167
168
169 default:
170
171 break;
172
173 }
174 link = forwards ? NextDown(link) : PrevDown(link);
175 }
176 debug1(DGA, D, "] SearchGalley returning %s", EchoIndex(res));
177 return res;
178 } /* end SearchGalley */
179
180
181 /*@@**************************************************************************/
182 /* */
183 /* int AttachGalley(hd, inners, suspend_pt) */
184 /* */
185 /* Attach galley hd, which may be unsized, to a destination. This involves */
186 /* searching for a destination forward or back from the attachment point of */
187 /* hd and promoting up to and including the first definite component of hd. */
188 /* */
189 /* Although AttachGalley never flushes any galleys, it may identify some */
190 /* galleys which should be flushed, even if the attach is itself not */
191 /* successful. These are returned in *inners, or nilobj if none. */
192 /* */
193 /* The integer returned by AttachGalley indicates what happened to hd: */
194 /* */
195 /* ATTACH_KILLED The galley was sized to begin with but no target */
196 /* for it could be found. The galley has been killed */
197 /* and that's the end of it. */
198 /* */
199 /* ATTACH_INPUT When searching for a target for the galley we came */
200 /* upon InputSym, suggesting that the target might be */
201 /* still to be read. So the galley has been linked to */
202 /* that InputSym and must now wait. */
203 /* */
204 /* ATTACH_NOTARGET The galley is unsized and no target could be found */
205 /* for it. This is fine, it just means that we can't */
206 /* flush the galley now and we must try again later. */
207 /* */
208 /* ATTACH_SUSPEND The galley is sized and a target was found for it, */
209 /* but the first component of the galley proved to be */
210 /* indefinite so could not be promoted. The galley */
211 /* remains unattached but is moved to just before its */
212 /* target so that it can find it easily later when its */
213 /* first component becomes definite and it is flushed. */
214 /* */
215 /* ATTACH_NULL The galley is sized and a target was found for it, */
216 /* but the body of the galley proved to be null (i.e. */
217 /* there were no definite components to be flushed). */
218 /* This is to be treated just like the normal case */
219 /* following, except that the target is replaced by */
220 /* @Null rather than by its body. */
221 /* */
222 /* ATTACH_ACCEPT The galley is sized and a target was found for it, */
223 /* and one component of the galley has been promoted. */
224 /* */
225 /*****************************************************************************/
226
AttachGalley(OBJECT hd,OBJECT * inners,OBJECT * suspend_pt)227 int AttachGalley(OBJECT hd, OBJECT *inners, OBJECT *suspend_pt)
228 { OBJECT hd_index; /* the index of hd in the enclosing galley */
229 OBJECT hd_inners; /* inner galleys of hd, if unsized */
230 OBJECT dest; /* the target @Galley hd empties into */
231 OBJECT dest_index; /* the index of dest */
232 OBJECT target; /* the target indefinite containing dest */
233 OBJECT target_index; /* the index of target */
234 OBJECT target_galley; /* the body of target, made into a galley */
235 OBJECT tg_inners; /* inner galleys of target_galley */
236 BOOLEAN need_precedes = FALSE;/* true if destination lies before galley */
237 OBJECT recs; /* list of recursive definite objects */
238 OBJECT link, y = nilobj; /* for scanning through the components of hd */
239 CONSTRAINT c; /* temporary variable holding a constraint */
240 OBJECT env, n1, tmp, zlink, z, sym; /* placeholders and temporaries */
241 BOOLEAN was_sized; /* true if sized(hd) initially */
242 int dim; /* the galley direction */
243 FULL_LENGTH perp_back, perp_fwd;
244 OBJECT why, junk;
245
246 debug2(DGA, D, "[ AttachGalley(Galley %s into %s)",
247 SymName(actual(hd)), SymName(whereto(hd)));
248 ifdebug(DGA, DD, DebugGalley(hd, nilobj, 4));
249 assert( Up(hd) != hd, "AttachGalley: no index!" );
250 Parent(hd_index, Up(hd));
251 assert( type(hd_index) == UNATTACHED, "AttachGalley: not UNATTACHED!" );
252 hd_inners = tg_inners = nilobj;
253 was_sized = sized(hd);
254 dim = gall_dir(hd);
255
256 for(;;)
257 {
258 /*************************************************************************/
259 /* */
260 /* Search for a destination for hd. If hd is unsized, search for */
261 /* inner galleys preceding it first of all, then for receptive objects */
262 /* following it, possibly in inner galleys. If no luck, exit. */
263 /* If hd is sized, search only for receptive objects in the current */
264 /* galley below the current spot, and fail if cannot find any. */
265 /* */
266 /*************************************************************************/
267
268 sym = whereto(hd);
269 if( sized(hd) )
270 {
271 /* sized galley case: search on from current spot */
272 target_index = SearchGalley(Up(hd_index), sym, TRUE, FALSE, TRUE, TRUE);
273 if( target_index == nilobj )
274 {
275 /* search failed to find any new target, so kill the galley */
276 for( link = Down(hd); link != hd; link = NextDown(link) )
277 { Child(y, link);
278 if( type(y) == SPLIT ) Child(y, DownDim(y, dim));
279 if( is_definite(type(y)) ) break;
280 }
281 if( link != hd )
282 Error(19, 1, "galley %s deleted from here (no target)",
283 WARN, &fpos(y), SymName(actual(hd)));
284 if( hd_inners != nilobj ) DisposeObject(hd_inners), hd_inners=nilobj;
285 if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners=nilobj;
286 KillGalley(hd, FALSE);
287 *inners = nilobj;
288 debug0(DGA, D, "] AttachGalley returning ATTACH_KILLED");
289 return ATTACH_KILLED;
290 }
291 else if( actual(actual(target_index)) == InputSym )
292 {
293 /* search found input object, so suspend on that */
294 DeleteNode(hd_index);
295 Link(target_index, hd);
296 *inners = nilobj;
297 debug0(DGA, D, "] AttachGalley returning ATTACH_INPUT");
298 return ATTACH_INPUT;
299 }
300
301 }
302 else /* unsized galley, either backwards or normal */
303 {
304 if( foll_or_prec(hd) == GALL_PREC )
305 { target_index= SearchGalley(Up(hd_index), sym, FALSE, TRUE,TRUE,FALSE);
306 need_precedes = FALSE;
307 }
308 else
309 { target_index = SearchGalley(Up(hd_index), sym, FALSE,TRUE,FALSE,FALSE);
310 need_precedes = (target_index != nilobj);
311 if( target_index == nilobj )
312 target_index = SearchGalley(Up(hd_index), sym, TRUE,TRUE,TRUE,FALSE);
313 }
314
315 /* if no luck, exit without error */
316 if( target_index == nilobj )
317 { *inners = nilobj;
318 debug0(DGA, D, "] AttachGalley returning ATTACH_NOTARGET");
319 return ATTACH_NOTARGET;
320 }
321 }
322 assert( type(target_index) == RECEPTIVE, "AttachGalley: target_index!" );
323 target = actual(target_index);
324 assert( type(target) == CLOSURE, "AttachGalley: target!" );
325
326 /* set target_galley to the expanded value of target */
327 debug1(DYY, D, "[ EnterErrorBlock(FALSE) (expanding target %s)",
328 SymName(actual(target)));
329 EnterErrorBlock(FALSE);
330 New(target_galley, HEAD);
331 force_gall(target_galley) = FALSE;
332 actual(target_galley) = actual(target);
333 enclose_obj(target_galley) = limiter(target_galley) = nilobj;
334 ClearHeaders(target_galley);
335 opt_components(target_galley) = opt_constraints(target_galley) = nilobj;
336 gall_dir(target_galley) = external_hor(target) ? COLM : ROWM;
337 FposCopy(fpos(target_galley), fpos(target));
338 whereto(target_galley) = ready_galls(target_galley) = nilobj;
339 foll_or_prec(target_galley) = GALL_FOLL;
340 must_expand(target_galley) = FALSE;
341 sized(target_galley) = FALSE;
342 seen_nojoin(target_galley) = FALSE;
343
344 /* get perpendicular constraint (none if horizontal galley) */
345 if( dim == ROWM )
346 {
347 Constrained(target, &c, 1-dim, &junk);
348 if( !constrained(c) )
349 Error(19, 2, "receptive symbol %s has unconstrained width",
350 FATAL, &fpos(target), SymName(actual(target)));
351 debug2(DSC, DD, "Constrained( %s, 1-dim ) = %s",
352 EchoObject(target), EchoConstraint(&c));
353 if( !FitsConstraint(0, 0, c) )
354 { debug0(DGA, D, " reject: target_galley horizontal constraint is -1");
355 y = nilobj;
356 goto REJECT;
357 }
358 }
359 else /* actually unused */
360 SetConstraint(c, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
361
362 debug1(DGA, DDD, " expanding %s", EchoObject(target));
363 tmp = CopyObject(target, no_fpos);
364 Link(target_galley, tmp);
365 env = DetachEnv(tmp);
366 debug4(DGM, D, " external_ver(%s) = %s, external_hor(%s) = %s",
367 SymName(actual(target)), bool(external_ver(target)),
368 SymName(actual(target)), bool(external_hor(target)));
369 SizeGalley(target_galley, env,
370 external_ver(target) || external_hor(target),
371 threaded(target), non_blocking(target_index),
372 trigger_externs(target_index), &save_style(target),
373 &c, whereto(hd), &dest_index, &recs, &tg_inners,
374 enclose_obj(hd) != nilobj ? CopyObject(enclose_obj(hd), no_fpos):nilobj);
375 debug1(DGA, D, " AttachGalley tg_inners: %s", DebugInnersNames(tg_inners));
376 if( recs != nilobj ) ExpandRecursives(recs);
377 dest = actual(dest_index);
378 if( underline(dest) == UNDER_UNDEF ) underline(dest) = UNDER_OFF;
379
380 /* verify that hd satisfies any horizontal constraint on dest */
381 if( dim == ROWM )
382 {
383 debug1(DGA, DDD, " checking hor fit of hd in %s",SymName(actual(dest)));
384 Constrained(dest, &c, 1-dim, &junk);
385 debug3(DSC, DD, "Constrained( %s, %s ) = %s",
386 EchoObject(dest), dimen(1-dim), EchoConstraint(&c));
387 assert( constrained(c), "AttachGalley: dest unconstrained!" );
388 if( !FitsConstraint(0, 0, c) )
389 { debug0(DGA, D, " reject: hd horizontal constraint is -1");
390 y = nilobj;
391 goto REJECT;
392 }
393 }
394
395 /* manifest and size the galley if not done yet */
396 if( !sized(hd) )
397 {
398 debug2(DYY, D, "[ EnterErrorBlock(TRUE) (sizing galley %s into %s)",
399 SymName(actual(hd)), SymName(whereto(hd)));
400 EnterErrorBlock(TRUE);
401 n1 = nilobj;
402 Child(y, Down(hd));
403 env = DetachEnv(y);
404 /*** threaded() only defined in ROWM case
405 SizeGalley(hd, env, TRUE, threaded(dest), non_blocking(target_index),
406 TRUE, &save_style(dest), &c, nilobj, &n1, &recs, &hd_inners);
407 *** */
408 SizeGalley(hd, env, TRUE, dim == ROWM ? threaded(dest) : FALSE,
409 non_blocking(target_index), TRUE, &save_style(dest), &c, nilobj,
410 &n1, &recs, &hd_inners, nilobj);
411 debug1(DGA, D," AttachGalley hd_inners: %s",DebugInnersNames(hd_inners));
412 if( recs != nilobj ) ExpandRecursives(recs);
413 if( need_precedes ) /* need an ordering constraint */
414 { OBJECT index1, index2;
415 New(index1, PRECEDES);
416 New(index2, FOLLOWS);
417 blocked(index2) = FALSE;
418 tmp = MakeWord(WORD, STR_EMPTY, no_fpos);
419 Link(index1, tmp); Link(index2, tmp);
420 Link(Up(hd_index), index1);
421 Link(Down(hd), index2);
422 debug0(DGA, D, " inserting PRECEDES and FOLLOWS");
423 }
424 LeaveErrorBlock(TRUE);
425 debug0(DYY, D, "] LeaveErrorBlock(TRUE) (finished sizing galley)");
426 }
427
428 if( dim == ROWM )
429 { if( !FitsConstraint(back(hd, 1-dim), fwd(hd, 1-dim), c) )
430 { debug3(DGA, D, " reject: hd %s,%s does not fit target_galley %s",
431 EchoLength(back(hd, 1-dim)), EchoLength(fwd(hd, 1-dim)),
432 EchoConstraint(&c));
433 Error(19, 3, "too little horizontal space for galley %s at %s",
434 WARN, &fpos(hd), SymName(actual(hd)), SymName(actual(dest)));
435 goto REJECT;
436 }
437 }
438
439 /* check status of first component of hd */
440 debug0(DGA, DDD, " now ready to attach; hd =");
441 ifdebug(DGA, DDD, DebugObject(hd));
442 for( link = Down(hd); link != hd; link = NextDown(link) )
443 {
444 Child(y, link);
445 debug1(DGA, DDD, " examining %s", EchoIndex(y));
446 if( type(y) == SPLIT ) Child(y, DownDim(y, dim));
447 switch( type(y) )
448 {
449
450 case EXPAND_IND:
451 case SCALE_IND:
452 case COVER_IND:
453 case GALL_PREC:
454 case GALL_FOLL:
455 case GALL_FOLL_OR_PREC:
456 case GALL_TARG:
457 case CROSS_PREC:
458 case CROSS_FOLL:
459 case CROSS_FOLL_OR_PREC:
460 case CROSS_TARG:
461 case PAGE_LABEL_IND:
462
463 break;
464
465
466 case PRECEDES:
467 case UNATTACHED:
468
469 if( was_sized )
470 { /* SizeGalley was not called, so hd_inners was not set by it */
471 if( hd_inners == nilobj ) New(hd_inners, ACAT);
472 Link(hd_inners, y);
473 }
474 break;
475
476
477 case RECEPTIVE:
478
479 goto SUSPEND;
480
481
482 case RECEIVING:
483
484 goto SUSPEND;
485
486
487 case FOLLOWS:
488
489 Child(tmp, Down(y));
490 if( Up(tmp) == LastUp(tmp) )
491 { link = pred(link, CHILD);
492 debug0(DGA, DD, " disposing FOLLOWS");
493 DisposeChild(NextDown(link));
494 break;
495 }
496 Parent(tmp, Up(tmp));
497 assert(type(tmp) == PRECEDES, "Attach: PRECEDES!");
498 switch( CheckComponentOrder(tmp, target_index) )
499 {
500 case CLEAR: DeleteNode(tmp);
501 link = pred(link, CHILD);
502 DisposeChild(NextDown(link));
503 break;
504
505 case PROMOTE: break;
506
507 case BLOCK: debug0(DGA, DD, "CheckContraint: BLOCK");
508 goto SUSPEND;
509
510 case CLOSE: debug0(DGA, D, " reject: CheckContraint");
511 goto REJECT;
512 }
513 break;
514
515
516 case GAP_OBJ:
517
518 underline(y) = underline(dest);
519 if( !join(gap(y)) ) seen_nojoin(hd) = TRUE;
520 break;
521
522
523 case BEGIN_HEADER:
524 case END_HEADER:
525 case SET_HEADER:
526 case CLEAR_HEADER:
527
528 /* do nothing until actually promoted out of here */
529 underline(y) = underline(dest);
530 break;
531
532
533 case CLOSURE:
534 case CROSS:
535 case FORCE_CROSS:
536 case NULL_CLOS:
537 case PAGE_LABEL:
538
539 underline(y) = underline(dest);
540 break;
541
542
543 case WORD:
544 case QWORD:
545 case ONE_COL:
546 case ONE_ROW:
547 case WIDE:
548 case HIGH:
549 case HSHIFT:
550 case VSHIFT:
551 case HMIRROR:
552 case VMIRROR:
553 case HSCALE:
554 case VSCALE:
555 case HCOVER:
556 case VCOVER:
557 case HCONTRACT:
558 case VCONTRACT:
559 case HLIMITED:
560 case VLIMITED:
561 case HEXPAND:
562 case VEXPAND:
563 case START_HVSPAN:
564 case START_HSPAN:
565 case START_VSPAN:
566 case HSPAN:
567 case VSPAN:
568 case ROTATE:
569 case BACKGROUND:
570 case SCALE:
571 case KERN_SHRINK:
572 case INCGRAPHIC:
573 case SINCGRAPHIC:
574 case PLAIN_GRAPHIC:
575 case GRAPHIC:
576 case LINK_SOURCE:
577 case LINK_DEST:
578 case LINK_DEST_NULL:
579 case LINK_URL:
580 case ACAT:
581 case HCAT:
582 case VCAT:
583 case ROW_THR:
584 case COL_THR:
585
586
587 underline(y) = underline(dest);
588 if( dim == ROWM )
589 {
590 /* make sure y is not joined to a target below (vertical only) */
591 for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) )
592 { Child(z, zlink);
593 switch( type(z) )
594 {
595 case RECEPTIVE:
596
597 if( non_blocking(z) )
598 { zlink = PrevDown(zlink);
599 DeleteNode(z);
600 }
601 else
602 { y = z;
603 goto SUSPEND;
604 }
605 break;
606
607
608 case RECEIVING:
609
610 if( non_blocking(z) )
611 { zlink = PrevDown(zlink);
612 while( Down(z) != z )
613 { Child(tmp, Down(y));
614 if( opt_components(tmp) != nilobj )
615 { DisposeObject(opt_components(tmp));
616 opt_components(tmp) = nilobj;
617 debug3(DOG, D, "AttachGalley(%s) de-optimizing %s %s",
618 SymName(actual(hd)), SymName(actual(tmp)), "(join)");
619 }
620 DetachGalley(tmp);
621 KillGalley(tmp, FALSE);
622 }
623 DeleteNode(z);
624 }
625 else
626 { y = z;
627 goto SUSPEND;
628 }
629 break;
630
631
632 case GAP_OBJ:
633
634 if( !join(gap(z)) ) zlink = PrevDown(hd);
635 break;
636
637
638 default: break;
639 }
640 }
641
642 /* if HCAT, try vertical hyphenation (vertical galleys only) */
643 if( type(y) == HCAT ) VerticalHyphenate(y);
644 }
645
646
647 /* check availability of parallel space for the first component */
648 why = nilobj;
649 Constrained(dest, &c, dim, &why);
650 debug3(DGF, DD, " dest parallel Constrained(%s, %s) = %s",
651 EchoObject(dest), dimen(dim), EchoConstraint(&c));
652 if( !FitsConstraint(back(y, dim), fwd(y, dim), c) )
653 { BOOLEAN scaled;
654
655 /* if forcing galley doesn't fit, try scaling first component */
656 scaled = FALSE;
657 if( force_gall(hd) && size(y, dim) > 0 )
658 { int scale_factor;
659 scale_factor = ScaleToConstraint(back(y,dim), fwd(y,dim), &c);
660 if( scale_factor > 0.5 * SF )
661 { char num1[20], num2[20];
662 sprintf(num1, "%.1fc", (float) size(y, dim) / CM);
663 sprintf(num2, "%.1fc", (float) bfc(c) / CM);
664 if( dim == ROWM )
665 Error(19, 4, "%s object too high for %s space; %s inserted",
666 WARN, &fpos(y), num1, num2, KW_SCALE);
667 else
668 Error(19, 5, "%s object too wide for %s space; %s inserted",
669 WARN, &fpos(y), num1, num2, KW_SCALE);
670 y = InterposeScale(y, scale_factor, dim);
671 scaled = TRUE;
672 }
673 }
674
675 /* otherwise we must reject, and warn the user */
676 if( !scaled )
677 { char num1[20], num2[20];
678 debug3(DGA, D, " reject: vsize %s,%s in %s; y=",
679 EchoLength(back(y, dim)), EchoLength(fwd(y, dim)),
680 EchoConstraint(&c));
681 ifdebug(DGA, DD, DebugObject(y));
682 if( size(y, dim) > 0 )
683 { sprintf(num1, "%.1fc", (float) size(y, dim) / CM);
684 sprintf(num2, "%.1fc", (float) bfc(c) / CM);
685 if( dim == ROWM )
686 Error(19, 12, "%s object too high for %s space; will try elsewhere",
687 WARN, &fpos(y), num1, num2);
688 else
689 Error(19, 13, "%s object too wide for %s space; will try elsewhere",
690 WARN, &fpos(y), num1, num2);
691 }
692 goto REJECT;
693 }
694
695 }
696
697 /* check availability of perpendicular space for first component */
698 if( dim == ROWM )
699 { perp_back = back(hd, 1-dim); perp_fwd = fwd(hd, 1-dim);
700 }
701 else
702 { perp_back = back(y, 1-dim); perp_fwd = fwd(y, 1-dim);
703 }
704 Constrained(dest, &c, 1-dim, &junk);
705 debug3(DGF, DD, " dest perpendicular Constrained(%s, %s) = %s",
706 EchoObject(dest), dimen(1-dim), EchoConstraint(&c));
707 if( !FitsConstraint(perp_back, perp_fwd, c) )
708 { BOOLEAN scaled;
709
710 /* if forcing galley doesn't fit, try scaling first component */
711 scaled = FALSE;
712 if( force_gall(hd) && perp_back + perp_fwd > 0 )
713 { int scale_factor;
714 scale_factor = ScaleToConstraint(perp_back, perp_fwd, &c);
715 if( scale_factor > 0.5 * SF )
716 { char num1[20], num2[20];
717 sprintf(num1, "%.1fc", (float) (perp_back + perp_fwd) / CM);
718 sprintf(num2, "%.1fc", (float) bfc(c) / CM);
719 if( 1-dim == ROWM )
720 Error(19, 6, "%s object too high for %s space; %s inserted",
721 WARN, &fpos(y), num1, num2, KW_SCALE);
722 else
723 Error(19, 7, "%s object too wide for %s space; %s inserted",
724 WARN, &fpos(y), num1, num2, KW_SCALE);
725 y = InterposeScale(y, scale_factor, 1-dim);
726 scaled = TRUE;
727 }
728 }
729
730 /* otherwise we must reject, and warn the user */
731 if( !scaled )
732 {
733 debug3(DGA, D, " reject: vsize %s,%s in %s; y=",
734 EchoLength(perp_back), EchoLength(perp_fwd),
735 EchoConstraint(&c));
736 ifdebug(DGA, DD, DebugObject(y));
737 goto REJECT;
738 }
739
740 }
741
742 /* dest seems OK, so perform its size adjustments */
743 debug0(DSA, D, "calling AdjustSize from AttachGalley (a)");
744 AdjustSize(dest, back(y, dim), fwd(y, dim), dim);
745 debug0(DSA, D, "calling AdjustSize from AttachGalley (b)");
746 AdjustSize(dest, perp_back, perp_fwd, 1-dim);
747
748
749 /* now check parallel space for target_galley in target */
750 Constrained(target, &c, dim, &why);
751 debug3(DGF, DD, " target parallel Constrained(%s, %s) = %s",
752 EchoObject(target), dimen(dim), EchoConstraint(&c));
753 Child(z, LastDown(target_galley)); /* works in all cases? */
754 assert( !is_index(type(z)), "AttachGalley: is_index(z)!" );
755 assert( back(z, dim)>=0 && fwd(z, dim)>=0, "AttachGalley: z size!" );
756 if( !FitsConstraint(back(z, dim), fwd(z, dim), c) )
757 { BOOLEAN scaled;
758
759 debug2(DGA, DD, " why = %d %s", (int) why, EchoObject(why));
760 debug2(DGA, DD, " limiter = %d %s", (int) limiter(hd),
761 EchoObject(limiter(hd)));
762
763 /* if forcing galley doesn't fit, try scaling z */
764 scaled = FALSE;
765 if( force_gall(hd) && size(z, dim) > 0 && limiter(hd) != why )
766 { int scale_factor;
767 scale_factor = ScaleToConstraint(back(z,dim), fwd(z,dim), &c);
768 if( scale_factor > 0.5 * SF )
769 { char num1[20], num2[20];
770 sprintf(num1, "%.1fc", (float) size(z, dim) / CM);
771 sprintf(num2, "%.1fc", (float) bfc(c) / CM);
772 if( dim == ROWM )
773 Error(19, 8, "%s object too high for %s space; %s inserted",
774 WARN, &fpos(y), num1, num2, KW_SCALE);
775 else
776 Error(19, 9, "%s object too wide for %s space; %s inserted",
777 WARN, &fpos(y), num1, num2, KW_SCALE);
778 z = InterposeWideOrHigh(z, dim);
779 z = InterposeScale(z, scale_factor, dim);
780 scaled = TRUE;
781 }
782 }
783
784 if( !scaled )
785 { char num1[20], num2[20];
786 limiter(hd) = why;
787 debug3(DGA, D, " set limiter(%s) = %d %s", SymName(actual(hd)),
788 (int) limiter(hd), EchoObject(limiter(hd)));
789 debug3(DGA, D, " reject: size was %s,%s in %s; y =",
790 EchoLength(back(z, dim)), EchoLength(fwd(z, dim)),
791 EchoConstraint(&c));
792 ifdebug(DGA, DD, DebugObject(y));
793 if( size(z, dim) > 0 )
794 { sprintf(num1, "%.1fc", (float) size(z, dim) / CM);
795 sprintf(num2, "%.1fc", (float) bfc(c) / CM);
796 if( dim == ROWM )
797 Error(19, 14, "%s object too high for %s space; will try elsewhere",
798 WARN, &fpos(y), num1, num2);
799 else
800 Error(19, 15, "%s object too wide for %s space; will try elsewhere",
801 WARN, &fpos(y), num1, num2);
802 }
803 goto REJECT;
804 }
805 }
806 limiter(hd) = why;
807 debug3(DGA, DD, " set limiter(%s) = %d %s", SymName(actual(hd)),
808 (int) limiter(hd), EchoObject(limiter(hd)));
809
810 /* now check perpendicular space for target_galley in target */
811 Constrained(target, &c, 1-dim, &junk);
812 debug3(DGF, DD, " target perpendicular Constrained(%s, %s) = %s",
813 EchoObject(target), dimen(1-dim), EchoConstraint(&c));
814 Child(z, LastDown(target_galley)); /* works in all cases? */
815 assert( !is_index(type(z)), "AttachGalley: is_index(z)!" );
816 assert( back(z, 1-dim)>=0 && fwd(z, 1-dim)>=0,
817 "AttachGalley: z size (perpendicular)!" );
818 if( !FitsConstraint(back(z, 1-dim), fwd(z, 1-dim), c) )
819 { BOOLEAN scaled;
820
821 /* if forcing galley doesn't fit, try scaling z */
822 scaled = FALSE;
823 if( force_gall(hd) && size(z, 1-dim) > 0 )
824 { int scale_factor;
825 scale_factor = ScaleToConstraint(back(z,1-dim), fwd(z,1-dim), &c);
826 if( scale_factor > 0.5 * SF )
827 { char num1[20], num2[20];
828 sprintf(num1, "%.1fc", (float) size(z, 1-dim) / CM);
829 sprintf(num2, "%.1fc", (float) bfc(c) / CM);
830 if( 1-dim == ROWM )
831 Error(19, 10, "%s object too high for %s space; %s inserted",
832 WARN, &fpos(y), num1, num2, KW_SCALE);
833 else
834 Error(19, 11, "%s object too wide for %s space; %s inserted",
835 WARN, &fpos(y), num1, num2, KW_SCALE);
836 z = InterposeWideOrHigh(z, 1-dim);
837 z = InterposeScale(z, scale_factor, 1-dim);
838 scaled = TRUE;
839 }
840 }
841
842 if( !scaled )
843 {
844 debug3(DGA, D, " reject: size was %s,%s in %s; y =",
845 EchoLength(back(z, 1-dim)), EchoLength(fwd(z, 1-dim)),
846 EchoConstraint(&c));
847 ifdebug(DGA, DD, DebugObject(y));
848 goto REJECT;
849 }
850 }
851
852 /* target seems OK, so adjust sizes and accept */
853 if( external_hor(target) )
854 {
855 /* don't adjust any sizes, none to adjust */
856 debug0(DSA, D, "not calling AdjustSize from AttachGalley (c)");
857 }
858 else if( external_ver(target) )
859 {
860 /* adjust perp size only, to galley size */
861 debug0(DSA, D, "calling AdjustSize from AttachGalley (d)");
862 AdjustSize(target, back(target_galley, 1-dim),
863 fwd(target_galley, 1-dim), 1-dim);
864 }
865 else
866 {
867 /* adjust both directions, using z (last component) */
868 Child(z, LastDown(target_galley));
869 debug0(DSA, D, "AttachGalley AdjustSize using z =");
870 ifdebug(DSA, D, DebugObject(z));
871 debug0(DSA, D, "calling AdjustSize from AttachGalley (e)");
872 AdjustSize(target, back(z, dim), fwd(z, dim), dim);
873 debug0(DSA, D, "calling AdjustSize from AttachGalley (f)");
874 AdjustSize(target, back(z, 1-dim), fwd(z, 1-dim), 1-dim);
875 }
876
877 goto ACCEPT;
878
879
880 default:
881
882 assert1(FALSE, "AttachGalley:", Image(type(y)));
883 break;
884
885 } /* end switch */
886 } /* end for */
887
888 /* null galley: promote whole galley without expanding the target */
889 debug0(DGA, D, " null galley");
890 if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners = nilobj;
891 DisposeObject(target_galley);
892 LeaveErrorBlock(FALSE);
893 debug0(DYY, D, "] LeaveErrorBlock(FALSE) (null galley)");
894
895 /* kill off any null objects within the galley, then transfer it */
896 /* don't use Promote() since it does extra unwanted things here */
897 for( link = Down(hd); link != hd; link = NextDown(link) )
898 { Child(y, link);
899 switch( type(y) )
900 {
901
902 case GAP_OBJ:
903 case CLOSURE:
904 case CROSS:
905 case FORCE_CROSS:
906 case NULL_CLOS:
907 case PAGE_LABEL:
908
909 link = PrevDown(link);
910 debug1(DGA, D, " null galley, disposing %s", Image(type(y)));
911 DisposeChild(NextDown(link));
912 break;
913
914
915 default:
916
917 break;
918 }
919 }
920 TransferLinks(NextDown(hd), hd, Up(target_index));
921
922 /* attach hd temporarily to target_index */
923 MoveLink(Up(hd), target_index, PARENT);
924 assert( type(hd_index) == UNATTACHED, "AttachGalley: type(hd_index)!" );
925 DeleteNode(hd_index);
926
927 /* return; only hd_inners needs to be flushed now */
928 *inners = hd_inners;
929 debug0(DGA, D, "] AttachGalley returning ATTACH_NULL");
930 return ATTACH_NULL;
931
932
933 REJECT:
934
935 /* reject first component */
936 /* debug1(DGA, D, " reject %s", EchoObject(y)); */
937 debug0(DGA, D, " reject first component");
938 LeaveErrorBlock(TRUE);
939 debug0(DYY, D, "] LeaveErrorBlock(TRUE) (REJECT)");
940 if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners = nilobj;
941 DisposeObject(target_galley);
942 if( foll_or_prec(hd) == GALL_PREC && !sized(hd) )
943 {
944 /* move to just before the failed target */
945 MoveLink(Up(hd_index), Up(target_index), PARENT);
946 }
947 else
948 {
949 /* move to just after the failed target */
950 MoveLink(Up(hd_index), NextDown(Up(target_index)), PARENT);
951 }
952 continue;
953
954
955 SUSPEND:
956
957 /* suspend at first component */
958 debug1(DGA, D, " suspend %s", EchoIndex(y));
959 blocked(y) = TRUE;
960 LeaveErrorBlock(FALSE);
961 debug0(DYY, D, "] LeaveErrorBlock(FALSE) (SUSPEND)");
962 if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners = nilobj;
963 DisposeObject(target_galley);
964 MoveLink(Up(hd_index), Up(target_index), PARENT);
965 if( was_sized )
966 { /* nothing new to flush if suspending and already sized */
967 if( hd_inners != nilobj ) DisposeObject(hd_inners), hd_inners=nilobj;
968 *inners = nilobj;
969 }
970 else
971 { /* flush newly discovered inners if not sized before */
972 *inners = hd_inners;
973 }
974 debug0(DGA, D, "] AttachGalley returning ATTACH_SUSPEND");
975 *suspend_pt = y;
976 return ATTACH_SUSPEND;
977
978
979 ACCEPT:
980
981 /* accept first component; now committed to the attach */
982 debug2(DGA, D, " accept first component %s %s", Image(type(y)),
983 EchoFilePos(&fpos(y)));
984 /* ***
985 debug3(DGA, DD, " accept %s %s %s", Image(type(y)), EchoObject(y),
986 EchoFilePos(&fpos(y)));
987 *** */
988 LeaveErrorBlock(TRUE);
989 debug0(DYY, D, "] LeaveErrorBlock(TRUE) (ACCEPT)");
990
991 /* attach hd to dest */
992 MoveLink(Up(hd), dest_index, PARENT);
993 assert( type(hd_index) == UNATTACHED, "AttachGalley: type(hd_index)!" );
994 DeleteNode(hd_index);
995
996 /* move first component of hd into dest */
997 /* nb Interpose must be done after all AdjustSize calls */
998 if( dim == ROWM && !external_ver(dest) )
999 Interpose(dest, VCAT, hd, y);
1000 else if( dim == COLM && !external_hor(dest) )
1001 { Interpose(dest, ACAT, y, y);
1002 Parent(junk, Up(dest));
1003 assert( type(junk) == ACAT, "AttachGalley: type(junk) != ACAT!" );
1004 StyleCopy(save_style(junk), save_style(dest));
1005 adjust_cat(junk) = padjust(save_style(junk));
1006 }
1007 debug1(DGS, D, "calling Promote(hd, %s) from AttachGalley/ACCEPT",
1008 link == hd ? "hd" : "NextDown(link)");
1009 Promote(hd, link == hd ? hd : NextDown(link), dest_index, TRUE);
1010
1011 /* move target_galley into target */
1012 /* nb Interpose must be done after all AdjustSize calls */
1013 if( !(external_ver(target) || external_hor(target)) )
1014 { Child(z, LastDown(target_galley));
1015 Interpose(target, VCAT, z, z);
1016 }
1017 debug0(DGS, D, "calling Promote(target_galley) from AttachGalley/ACCEPT");
1018 Promote(target_galley, target_galley, target_index, TRUE);
1019 DeleteNode(target_galley);
1020 assert(Down(target_index)==target_index, "AttachGalley: target_ind");
1021 if( blocked(target_index) ) blocked(dest_index) = TRUE;
1022 DeleteNode(target_index);
1023
1024 /* return; both tg_inners and hd_inners need to be flushed now; */
1025 /* if was_sized, hd_inners contains the inners of the first component; */
1026 /* otherwise it contains the inners of all components, from SizeGalley */
1027 if( tg_inners == nilobj ) *inners = hd_inners;
1028 else if( hd_inners == nilobj ) *inners = tg_inners;
1029 else
1030 { TransferLinks(Down(hd_inners), hd_inners, tg_inners);
1031 DeleteNode(hd_inners);
1032 *inners = tg_inners;
1033 }
1034 debug1(DGA, D, "] AttachGalley returning ATTACH_ACCEPT (inners %s)",
1035 DebugInnersNames(*inners));
1036 ifdebug(DGA, D,
1037 if( dim == COLM && !external_hor(dest) )
1038 { OBJECT z;
1039 Parent(z, Up(dest));
1040 debug2(DGA, D, " COLM dest_encl on exit = %s %s",
1041 Image(type(z)), EchoObject(z));
1042 }
1043 )
1044 return ATTACH_ACCEPT;
1045
1046 } /* end for */
1047 } /* end AttachGalley */
1048