1 /*@z23.c:Galley Printer:ScaleFactor()@****************************************/
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: z23.c */
26 /* MODULE: Galley Printer */
27 /* EXTERNS: FixAndPrintObject() */
28 /* */
29 /*****************************************************************************/
30 #include "externs.h"
31 #define NO_SUPPRESS FALSE
32 #define SUPPRESS TRUE
33 #define word_equal(x, str) (is_word(type(x)) && StringEqual(string(x), str))
34
35
36 /*****************************************************************************/
37 /* */
38 /* FirstDefiniteLDN(x, link, y, jn, ymk, dim, sp, pg) */
39 /* NextDefiniteWithGapLDN(x, link, y, g, jn, ymk, dim, sp, pg) */
40 /* */
41 /* Like FirstDefinite and NextDefiniteWithGap but during the scan, if a */
42 /* LINK_DEST_NULL is encountered, call FixAndPrintObject on it before */
43 /* continuing on to find the next definite object. */
44 /* */
45 /*****************************************************************************/
46
47 #define FirstDefiniteLDN(x, link, y, jn, ymk, dim, sp, pg) \
48 { jn = TRUE; \
49 for( link = Down(x); link != x; link = NextDown(link) ) \
50 { Child(y, link); \
51 if( type(y) == GAP_OBJ ) jn = jn && join(gap(y)); \
52 else if( type(y)==SPLIT ? SplitIsDefinite(y) : is_definite(type(y)))\
53 break; \
54 else if( type(y) == LINK_DEST_NULL ) \
55 FixAndPrintObject(y, ymk, 0, 0, dim, sp, pg, 0, &aback, &afwd); \
56 } \
57 } /* end FirstDefiniteLDN */
58
59 #define NextDefiniteWithGapLDN(x, link, y, g, jn, ymk, dim, sp, pg) \
60 { g = nilobj; jn = TRUE; \
61 for( link = NextDown(link); link != x; link = NextDown(link) ) \
62 { Child(y, link); \
63 if( type(y) == GAP_OBJ ) g = y, jn = jn && join(gap(y)); \
64 else if( type(y)==SPLIT ? SplitIsDefinite(y):is_definite(type(y)) ) \
65 { \
66 debug2(DFS, DD, " NextDefiniteWithGapLDN at %s %s", \
67 Image(type(y)), EchoObject(y)); \
68 assert( g != nilobj, "NextDefiniteWithGap: g == nilobj!" ); \
69 break; \
70 } \
71 else if( type(y) == LINK_DEST_NULL ) \
72 FixAndPrintObject(y, ymk, 0, 0, dim, sp, pg, 0, &aback, &afwd); \
73 } \
74 } /* end NextDefiniteWithGapLDN */
75
76
77
78 /*****************************************************************************/
79 /* */
80 /* static float ScaleFactor(avail_size, inner_size) */
81 /* */
82 /* Return the scale factor for this scaling, or 0 if impossible. */
83 /* */
84 /*****************************************************************************/
85
ScaleFactor(FULL_LENGTH avail_size,FULL_LENGTH inner_size)86 static float ScaleFactor(FULL_LENGTH avail_size, FULL_LENGTH inner_size)
87 { float scale_factor;
88 scale_factor = avail_size <= 0 ? 0 :
89 inner_size <= 0 ? 0 : (float) avail_size / inner_size;
90 return scale_factor;
91 }
92
93
94 /*@::FindAdjustIncrement()@***************************************************/
95 /* */
96 /* static FULL_LENGTH FindAdjustIncrement(x, frame_size, dim) */
97 /* */
98 /* Find the amount by which to increase the width of the subobjects of */
99 /* concatenation object x so that it is adjusted to fill size frame_size. */
100 /* */
101 /*****************************************************************************/
102
FindAdjustIncrement(OBJECT x,FULL_LENGTH frame_size,int dim)103 static FULL_LENGTH FindAdjustIncrement(OBJECT x, FULL_LENGTH frame_size,int dim)
104 { OBJECT y = nilobj, link, prev = nilobj, g;
105 int adjustable_gaps; BOOLEAN jn;
106 FULL_LENGTH inc, mk, actual_size;
107
108 debug2(DGP, DD, "FindAdjustIncrement(x, %s, %s)",
109 EchoLength(frame_size), dimen(dim));
110 FirstDefinite(x, link, prev, jn);
111 if( link != x )
112 { adjustable_gaps = 0;
113 mk = back(prev, dim);
114 NextDefiniteWithGap(x, link, y, g, jn);
115 while( link != x )
116 { if ( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
117 || units(gap(g)) == FRAME_UNIT )
118 { debug0(DGP, DD, "FindAdjustIncrement returning 0 (tab gap)");
119 return 0;
120 }
121 mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
122 frame_size, mk);
123 prev = y;
124 adjustable_gaps++;
125 NextDefiniteWithGap(x, link, y, g, jn);
126 }
127 actual_size = mk + fwd(prev, dim);
128 debug2(DGP, DD, " actual_size = %s, adjustable_gaps = %d",
129 EchoLength(actual_size), adjustable_gaps);
130 inc = adjustable_gaps==0 ? 0 : (frame_size - actual_size) / adjustable_gaps;
131 }
132 else inc = 0;
133 debug1(DGP, DD, "FindAdjustIncrement returning %s", EchoLength(inc));
134 return inc;
135 } /* end FindAdjustIncrement */
136
137
138 /*@::FixAndPrintObject()@*****************************************************/
139 /* */
140 /* OBJECT FixAndPrintObject(x, xmk, xb, xf, dim, suppress, pg, count, */
141 /* actual_back, actual_fwd) */
142 /* */
143 /* Fix the absolute position of object x in dimension dim, in such a way */
144 /* that the principal mark of x has coordinate xmk, and x has actual size */
145 /* (xb, xf), where usually xb >= back(x, dim) and xf >= fwd(x, dim). */
146 /* */
147 /* Actually, in the case where x includes an object lying on a thread */
148 /* leading outside x, the final size of x may be different. Because */
149 /* of this, the procedure sets *actual_back and *actual_fwd to the actual */
150 /* size of x upon return. The caller assumes that x will exactly occupy */
151 /* this space (actual_back, actual_fwd). */
152 /* */
153 /* The suppress parameter is true if a temporary suppression of adjustment */
154 /* in this direction is in effect (because a neighbouring adjustment has */
155 /* already been done). This is for @HAdjust and @VAdjust, not @PAdjust. */
156 /* */
157 /* If dim == COLM, the coordinate information is merely stored; but if */
158 /* dim == ROWM, it is used to generate PostScript for printing x. */
159 /* */
160 /* Parameter pg records the height of the current page. This is used */
161 /* to correct for the fact that Lout places its origin at the top left, */
162 /* while PostScript places its origin at the bottom left. This correction */
163 /* cannot be made by transforming user space. */
164 /* */
165 /* x is child number count of its parent (used by COL_THR and ROW_THR only) */
166 /* */
167 /* FixAndPrintObject ordinarily returns the object passed to it; however */
168 /* it occasionally replaces that object with another, and then it is the */
169 /* replacement object that is returned. */
170 /* */
171 /*****************************************************************************/
172
FixAndPrintObject(OBJECT x,FULL_LENGTH xmk,FULL_LENGTH xb,FULL_LENGTH xf,int dim,BOOLEAN suppress,FULL_LENGTH pg,int count,FULL_LENGTH * actual_back,FULL_LENGTH * actual_fwd)173 OBJECT FixAndPrintObject(OBJECT x, FULL_LENGTH xmk, FULL_LENGTH xb,
174 FULL_LENGTH xf, int dim, BOOLEAN suppress, FULL_LENGTH pg, int count,
175 FULL_LENGTH *actual_back, FULL_LENGTH *actual_fwd)
176 { OBJECT y = nilobj, link, prev = nilobj, g, z, face, thr, res, uplink;
177 /* OBJECT fixed_thr, tmp; */
178 FULL_LENGTH mk, ymk, frame_size, back_edge, yb, yf, inc, f;
179 FULL_LENGTH aback, afwd;
180 int i; float scale_factor; BOOLEAN jn;
181 debug8(DGP, DD, "[ FixAndPrintObject(%s %s%s, %s, %s,%s, %s, %s, pg, count)",
182 Image(type(x)),
183 ((type(x) == WORD || type(x) == QWORD) ? string(x) : STR_EMPTY),
184 EchoFilePos(&fpos(x)),
185 EchoLength(xmk), EchoLength(xb), EchoLength(xf),dimen(dim),
186 (suppress == SUPPRESS ? "suppress" : "no_suppress"));
187 debug2(DGP, DD, " size(x) = %s,%s; x =",
188 EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
189 ifdebug(DGP, DD, DebugObject(x));
190 res = x;
191
192 /*** start and stop debugging
193 if( dim == COLM && is_word(type(x)) &&
194 StringEqual(string(x), AsciiToFull("STARTBUG")) )
195 dbg[DGP].on[DD] = dbg[DGP].on[D] = TRUE;
196 if( dim == COLM && is_word(type(x)) &&
197 StringEqual(string(x), AsciiToFull("STOPBUG")) )
198 dbg[DGP].on[DD] = dbg[DGP].on[D] = FALSE;
199 *** */
200
201
202 switch( type(x) )
203 {
204
205 case CLOSURE:
206 case NULL_CLOS:
207 case PAGE_LABEL:
208 case CROSS:
209 case FORCE_CROSS:
210
211 *actual_back = xb; *actual_fwd = xf;
212 break;
213
214
215 case START_HVSPAN:
216 case START_HSPAN:
217 case START_VSPAN:
218
219 CountChild(y, DownDim(x, dim), count);
220 if( type(y) == HSPANNER || type(y) == VSPANNER )
221 {
222 Child(z, Down(y));
223 Parent(thr, UpDim(x, dim));
224 save_mark(y) = xmk - back(thr, dim) + back(z, dim);
225
226 /* do the fix now if the first column is also the last one */
227 debug2(DGP, DD, " pre-inc spanner_fixed(y) = %d, spanner_count(y) = %d",
228 spanner_fixed(y), spanner_count(y));
229 if( ++spanner_fixed(y) == spanner_count(y) )
230 {
231 debug6(DGP, DD, " f+last SPAN: yf = max(%s + %s - %s, %s, %s - %s)",
232 EchoLength(xmk), EchoLength(xf), EchoLength(save_mark(y)),
233 EchoLength(fwd(z, dim)),
234 EchoLength(bfc(constraint(y))), EchoLength(back(z, dim)));
235 yf = find_max(xmk + xf - save_mark(y), fwd(z, dim));
236 yf = find_max(yf, bfc(constraint(y)) - back(z, dim));
237 z = FixAndPrintObject(z, save_mark(y), back(z, dim), yf, dim,
238 FALSE, pg, 1, &aback, &afwd);
239 spanner_fixed(y) = 0; /* restart for if printed again */
240 }
241 *actual_back = back(x, dim); *actual_fwd = fwd(x, dim);
242 }
243 else
244 {
245 debug6(DGP, DD, "%s alternate FixAndPrintObject(%s, %s, %s, %s, %s, ..)",
246 Image(type(x)), Image(type(y)), EchoLength(xmk), EchoLength(xb),
247 EchoLength(xf), dimen(dim));
248 y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
249 actual_back, actual_fwd);
250 }
251 break;
252
253
254 case HSPAN:
255 case VSPAN:
256
257 /* do the fix on the last one */
258 if( (dim == COLM) == (type(x) == HSPAN) )
259 {
260 CountChild(y, DownDim(x, dim), count);
261 assert(type(y) == HSPANNER || type(y) == VSPANNER, "FAPO HSPAN/VSPAN!");
262 debug2(DGP, DD, " pre-inc spanner_fixed(y) = %d, spanner_count(y) = %d",
263 spanner_fixed(y), spanner_count(y));
264 if( ++spanner_fixed(y) == spanner_count(y) )
265 {
266 Child(z, Down(y));
267 debug6(DGP, DD, " last SPAN: yf = max(%s + %s - %s, %s, %s - %s)",
268 EchoLength(xmk), EchoLength(xf), EchoLength(save_mark(y)),
269 EchoLength(fwd(z, dim)),
270 EchoLength(bfc(constraint(y))), EchoLength(back(z, dim)));
271 yf = find_max(xmk + xf - save_mark(y), fwd(z, dim));
272 yf = find_max(yf, bfc(constraint(y)) - back(z, dim));
273 z = FixAndPrintObject(z, save_mark(y), back(z, dim), yf, dim,
274 FALSE, pg, 1, &aback, &afwd);
275 *actual_back = back(x, dim); *actual_fwd = fwd(x, dim);
276 spanner_fixed(y) = 0; /* restart for if printed again */
277 }
278 }
279 break;
280
281
282 case WORD:
283 case QWORD:
284
285 if( dim == COLM )
286 {
287 /* save horizontal position for PrintWord below */
288 word_save_mark(x) = xmk;
289
290 /* if first occurrence of this font on this page, notify font */
291 if( string(x)[0] != '\0' )
292 { face = finfo[word_font(x)].original_face;
293 if( font_page(face) < font_curr_page )
294 { debug3(DFT, DD, "FAPO: x = %s, word_font = %d, face = %s",
295 string(x), word_font(x), EchoObject(face));
296 FontPageUsed(face);
297 }
298 }
299 }
300 else
301 {
302 if( string(x)[0] != '\0' )
303 { BackEnd->PrintWord(x, word_save_mark(x), pg - xmk);
304 /* NB if this word is to be underlined, it will be already enclosed
305 in an ACAT by Manifest, and that ACAT will do the underlining */
306 }
307 }
308 *actual_back = xb; *actual_fwd = xf;
309 break;
310
311
312 case WIDE:
313 case HIGH:
314
315 CountChild(y, Down(x), count);
316 if( (dim == COLM) == (type(x) == WIDE) )
317 { yf = bfc(constraint(x)) - back(y, dim);
318 y = FixAndPrintObject(y, xmk, back(y,dim), yf, dim, NO_SUPPRESS, pg,
319 count, &aback, &afwd);
320 *actual_back = xb; *actual_fwd = xf;
321 }
322 else
323 { y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
324 actual_back, actual_fwd);
325 }
326 break;
327
328
329 case HSHIFT:
330 case VSHIFT:
331
332 CountChild(y, Down(x), count);
333 if( (dim == COLM) == (type(x) == HSHIFT) )
334 {
335 /* work out the size of the shift depending on the units */
336 f = FindShift(x, y, dim);
337 ymk = xmk - f;
338 yb = find_max(0, xb - f);
339 yf = find_max(0, xf + f);
340 y = FixAndPrintObject(y, ymk, yb, yf, dim, suppress, pg, count,
341 &aback, &afwd);
342
343 /* recalculate the size of x as in MinSize */
344 f = FindShift(x, y, dim);
345 *actual_back = find_min(MAX_FULL_LENGTH, find_max(0, aback + f));
346 *actual_fwd = find_min(MAX_FULL_LENGTH, find_max(0, afwd - f));
347 }
348 else
349 { y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
350 actual_back, actual_fwd);
351 }
352 break;
353
354
355 case HCONTRACT:
356 case VCONTRACT:
357
358 CountChild(y, Down(x), count);
359 if( (dim == COLM) == (type(x) == HCONTRACT) )
360 { y = FixAndPrintObject(y, xmk, back(y,dim), fwd(y,dim), dim,
361 NO_SUPPRESS, pg, count, &aback, &afwd);
362 *actual_back = xb; *actual_fwd = xf;
363 }
364 else
365 { y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
366 actual_back, actual_fwd);
367 }
368 break;
369
370
371 case ONE_COL:
372 case ONE_ROW:
373 case HLIMITED:
374 case VLIMITED:
375 case HEXPAND:
376 case VEXPAND:
377
378 CountChild(y, Down(x), count);
379 if( (dim == COLM) == (type(x) == ONE_COL || type(x) == HEXPAND) )
380 { y = FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
381 &aback, &afwd);
382 *actual_back = xb; *actual_fwd = xf;
383 }
384 else
385 { y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
386 actual_back, actual_fwd);
387 }
388 break;
389
390
391 case HMIRROR:
392
393 if( BackEnd->mirror_avail )
394 {
395 CountChild(y, Down(x), count);
396 if( dim == COLM )
397 {
398 save_mark(x) = xmk;
399 y = FixAndPrintObject(y, 0, back(y, COLM), fwd(y, COLM), dim,
400 NO_SUPPRESS, pg, count, &aback, &afwd);
401 }
402 else
403 { BackEnd->SaveGraphicState(y);
404 BackEnd->CoordTranslate(save_mark(x), pg - xmk);
405 BackEnd->CoordHMirror();
406 y = FixAndPrintObject(y, 0, back(y, ROWM), fwd(y, ROWM), dim,
407 NO_SUPPRESS, 0, count, &aback, &afwd);
408 BackEnd->RestoreGraphicState();
409 }
410 }
411 *actual_back = xb; *actual_fwd = xf;
412 break;
413
414
415 case VMIRROR:
416
417 debug0(DRS, DD, "FixAndPrintObject at VMIRROR");
418 if( BackEnd->mirror_avail )
419 {
420 CountChild(y, Down(x), count);
421 if( dim == COLM )
422 y = FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
423 &aback, &afwd);
424 else
425 { BackEnd->SaveGraphicState(y);
426 BackEnd->CoordTranslate(0, pg - xmk);
427 BackEnd->CoordVMirror();
428 y = FixAndPrintObject(y, 0, back(y, ROWM), fwd(y, ROWM), dim,
429 NO_SUPPRESS, 0, count, &aback, &afwd);
430 BackEnd->RestoreGraphicState();
431 }
432 }
433 *actual_back = xb; *actual_fwd = xf;
434 break;
435
436
437 case VSCALE:
438
439 debug0(DRS, DD, "FixAndPrintObject at VSCALE");
440 CountChild(y, Down(x), count);
441 if( BackEnd->scale_avail )
442 {
443 if( dim == COLM )
444 y = FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
445 &aback, &afwd);
446 else if( (scale_factor = ScaleFactor(xb+xf, size(y, ROWM))) > 0 )
447 { BackEnd->SaveGraphicState(y);
448 BackEnd->CoordTranslate(0,
449 pg - (xmk - xb + (FULL_LENGTH) (back(y, ROWM) * scale_factor)));
450 BackEnd->CoordScale(1.0, scale_factor);
451 y = FixAndPrintObject(y, 0, back(y,ROWM), fwd(y,ROWM), dim,
452 NO_SUPPRESS, 0, count, &aback, &afwd);
453 BackEnd->RestoreGraphicState();
454 }
455 else if( !is_word(type(y)) || string(y)[0] != '\0' )
456 Error(23, 1, "object deleted (it cannot be scaled vertically)",
457 WARN, &fpos(x));
458 }
459 *actual_back = xb; *actual_fwd = xf;
460 break;
461
462
463 case HSCALE:
464
465 debug0(DRS, DD, "FixAndPrintObject at HSCALE");
466 CountChild(y, Down(x), count);
467 if( BackEnd->scale_avail )
468 { if( dim == COLM )
469 { save_mark(x) = xmk;
470 bc(constraint(x)) = xb;
471 fc(constraint(x)) = xf;
472 if( (scale_factor = ScaleFactor(xb+xf, size(y, COLM))) > 0 )
473 y = FixAndPrintObject(y, 0, back(y, COLM), fwd(y, COLM), dim,
474 NO_SUPPRESS, pg, count, &aback, &afwd);
475 else if( !is_word(type(y)) || string(y)[0] != '\0' )
476 Error(23, 2, "object deleted (it cannot be scaled horizontally)",
477 WARN, &fpos(y));
478 }
479 else if( (scale_factor =
480 ScaleFactor(bc(constraint(x))+fc(constraint(x)),size(y,COLM))) > 0 )
481 { BackEnd->SaveGraphicState(y);
482 BackEnd->CoordTranslate(save_mark(x) - bc(constraint(x))
483 + (FULL_LENGTH) (back(y, COLM)*scale_factor), 0);
484 BackEnd->CoordScale(scale_factor, 1.0);
485 y = FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
486 &aback, &afwd);
487 BackEnd->RestoreGraphicState();
488 }
489 }
490 *actual_back = xb; *actual_fwd = xf;
491 break;
492
493
494 case SCALE:
495
496 CountChild(y, Down(x), count);
497 if( BackEnd->scale_avail )
498 {
499 if( dim == COLM )
500 { assert( bc(constraint(x)) > 0, "FAPO: horizontal scale factor!" );
501 save_mark(x) = xmk;
502 yb = xb * SF / bc(constraint(x));
503 yf = xf * SF / bc(constraint(x));
504 y = FixAndPrintObject(y, 0, yb, yf, dim, NO_SUPPRESS, pg, count,
505 &aback, &afwd);
506 }
507 else
508 { assert( fc(constraint(x)) > 0, "FAPO: vertical scale factor!" );
509 yb = xb * SF / fc(constraint(x));
510 yf = xf * SF / fc(constraint(x));
511 BackEnd->SaveGraphicState(y);
512 BackEnd->CoordTranslate(save_mark(x), pg - xmk);
513 BackEnd->CoordScale( (float)bc(constraint(x))/SF,
514 (float)fc(constraint(x))/SF);
515 y = FixAndPrintObject(y, 0, yb, yf, dim, NO_SUPPRESS, 0, count,
516 &aback, &afwd);
517 BackEnd->RestoreGraphicState();
518 }
519 }
520 else if( bc(constraint(x)) == SF && fc(constraint(x)) == SF )
521 {
522 y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
523 &aback, &afwd);
524 }
525 *actual_back = xb; *actual_fwd = xf;
526 break;
527
528
529 case KERN_SHRINK:
530
531 CountChild(y, LastDown(x), count);
532 if( dim == COLM )
533 { y = FixAndPrintObject(y, xmk, back(y,dim), fwd(y,dim), dim,
534 NO_SUPPRESS, pg, count, &aback, &afwd);
535 *actual_back = back(x, dim); *actual_fwd = fwd(x, dim);
536 }
537 else
538 { y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
539 actual_back, actual_fwd);
540 }
541 break;
542
543
544 case BACKGROUND:
545
546 /* this object has the size of its second child; but its first */
547 /* child gets printed too, in the same space */
548 CountChild(y, Down(x), count);
549 y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
550 &aback, &afwd);
551 CountChild(y, LastDown(x), count);
552 y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
553 &aback, &afwd);
554 *actual_back = back(x, dim); *actual_fwd = fwd(x, dim);
555 break;
556
557
558 case ROTATE:
559
560 CountChild(y, Down(x), count);
561 if( BackEnd->rotate_avail )
562 {
563 if( dim == COLM )
564 { CONSTRAINT colc, rowc, yc;
565 save_mark(x) = xmk;
566 SetConstraint(colc, back(x,COLM), MAX_FULL_LENGTH, fwd(x,COLM));
567 SetConstraint(rowc, back(x,ROWM), MAX_FULL_LENGTH, fwd(x,ROWM));
568 RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc,COLM);
569 y = FixAndPrintObject(y, 0, bc(yc), fc(yc), COLM, NO_SUPPRESS, pg,
570 count, &aback, &afwd);
571 }
572 else
573 { CONSTRAINT colc, rowc, yc;
574 BackEnd->SaveGraphicState(y);
575 BackEnd->CoordTranslate(save_mark(x), pg - xmk);
576 BackEnd->CoordRotate(sparec(constraint(x)));
577 SetConstraint(colc, back(x,COLM), MAX_FULL_LENGTH, fwd(x,COLM));
578 SetConstraint(rowc, back(x,ROWM), MAX_FULL_LENGTH, fwd(x,ROWM));
579 RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc, ROWM);
580 y = FixAndPrintObject(y, 0, bc(yc), fc(yc), ROWM, NO_SUPPRESS, 0,
581 count, &aback, &afwd);
582 BackEnd->RestoreGraphicState();
583 }
584 }
585 else if( sparec(constraint(x)) == 0 )
586 y = FixAndPrintObject(y,xmk,xb,xf,dim,suppress,pg,count,&aback,&afwd);
587 *actual_back = xb; *actual_fwd = xf;
588 break;
589
590
591 case PLAIN_GRAPHIC:
592
593 CountChild(y, LastDown(x), count);
594 if( BackEnd->plaingraphic_avail )
595 {
596 if( dim == COLM )
597 {
598 back(x, dim) = xb; /* NB state change here */
599 fwd(x, dim) = xf;
600 save_mark(x) = xmk - back(x, dim);
601 debug2(DGP, DD, "PLAIN_GRAPHIC COLM storing size %s, %s",
602 EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
603 y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
604 &aback, &afwd);
605 }
606 else
607 { OBJECT tmp, pre, post;
608 Child(tmp, Down(x));
609 if( type(tmp) == VCAT )
610 { Child(pre, Down(tmp));
611 Child(post, LastDown(tmp));
612 }
613 else pre = tmp, post = nilobj;
614 back(x, dim) = xb;
615 fwd(x, dim) = xf;
616 BackEnd->PrintPlainGraphic(pre, save_mark(x),
617 pg - (xmk - back(x, dim)), x);
618 y = FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count,
619 &aback, &afwd);
620 if( post != nilobj )
621 BackEnd->PrintPlainGraphic(post, save_mark(x),
622 pg - (xmk - back(x, dim)), x);
623 }
624 }
625 else
626 y = FixAndPrintObject(y, xmk,xb,xf,dim,suppress,pg,count,&aback,&afwd);
627 *actual_back = xb; *actual_fwd = xf;
628 break;
629
630
631 case GRAPHIC:
632
633 CountChild(y, LastDown(x), count);
634 if( BackEnd->graphic_avail )
635 {
636 if( dim == COLM )
637 {
638 /* if first occurrence of this font on this page, notify font */
639 if( font(save_style(x)) > 0 )
640 { face = finfo[font(save_style(x))].original_face;
641 if( font_page(face) < font_curr_page ) FontPageUsed(face);
642 }
643
644 back(x, dim) = xb; /* NB state change here */
645 fwd(x, dim) = xf;
646 debug2(DGP, DD, "GRAPHIC COLM storing size %s, %s",
647 EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
648 save_mark(x) = xmk - back(x, COLM);
649 y = FixAndPrintObject(y, xb, xb, xf, dim, NO_SUPPRESS, pg, count,
650 &aback, &afwd);
651 }
652 else
653 { OBJECT tmp, pre, post;
654 Child(tmp, Down(x));
655 if( type(tmp) == VCAT )
656 { Child(pre, Down(tmp));
657 Child(post, LastDown(tmp));
658 }
659 else pre = tmp, post = nilobj;
660 back(x, dim) = xb;
661 fwd(x, dim) = xf;
662
663 BackEnd->SaveTranslateDefineSave(x, save_mark(x),
664 pg - (xmk + fwd(x, ROWM)));
665 BackEnd->PrintGraphicObject(pre);
666 BackEnd->RestoreGraphicState();
667 y = FixAndPrintObject(y, xb, xb, xf, dim, NO_SUPPRESS, xb + xf,
668 count, &aback, &afwd);
669 if( post != nilobj ) BackEnd->PrintGraphicObject(post);
670 BackEnd->RestoreGraphicState();
671 }
672 }
673 else
674 y = FixAndPrintObject(y, xmk,xb,xf,dim,suppress,pg,count,&aback,&afwd);
675 *actual_back = xb; *actual_fwd = xf;
676 break;
677
678
679 case LINK_SOURCE:
680 case LINK_DEST:
681 case LINK_DEST_NULL:
682 case LINK_URL:
683
684 ifdebug(DGP, D,
685 Child(z, Down(x));
686 debug7(DGP, D, "[ FixAndPrintObject(%s %s%s, %s, %s, %s, %s, -)",
687 Image(type(x)),
688 ((type(x)==LINK_DEST || type(x)==LINK_DEST_NULL) ? string(z):STR_EMPTY),
689 type(x)==LINK_DEST_NULL ? " (indef)" : "",
690 EchoLength(xmk), EchoLength(xb), EchoLength(xf), dimen(dim));
691 );
692 CountChild(y, LastDown(x), count);
693 if( dim == COLM )
694 save_mark(x) = xmk;
695 else
696 { Child(z, Down(x));
697 switch( type(x) )
698 {
699 case LINK_SOURCE:
700
701 BackEnd->LinkSource(z, save_mark(x) - back(x, COLM),
702 (pg - xmk) - xf, save_mark(x) + fwd(x, COLM), (pg - xmk) + xb);
703 break;
704
705 case LINK_DEST:
706 case LINK_DEST_NULL:
707
708 BackEnd->LinkDest(z, save_mark(x) - back(x, COLM),
709 (pg - xmk) - xf, save_mark(x) + fwd(x, COLM), (pg - xmk) + xb);
710 break;
711
712 case LINK_URL:
713
714 BackEnd->LinkURL(z, save_mark(x) - back(x, COLM),
715 (pg - xmk) - xf, save_mark(x) + fwd(x, COLM), (pg - xmk) + xb);
716 break;
717 }
718 }
719 y = FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
720 &aback, &afwd);
721 *actual_back = xb; *actual_fwd = xf;
722 debug0(DGP, D, "] FixAndPrintObject returning");
723 break;
724
725
726 case INCGRAPHIC:
727 case SINCGRAPHIC:
728
729 CountChild(y, Down(x), count);
730 if( BackEnd->incgraphic_avail )
731 {
732 if( dim == COLM )
733 { save_mark(x) = xmk;
734 if( incgraphic_ok(x) )
735 { debug2(DGP, DD, " %s (style %s)",
736 EchoObject(x), EchoStyle(&save_style(x)));
737 face = finfo[font(save_style(x))].original_face;
738 if( font_page(face) < font_curr_page )
739 { debug3(DFT, DD, "FAPO-IG: x = %s, font = %d, face = %s",
740 string(x), font(save_style(x)), EchoObject(face));
741 FontPageUsed(face);
742 }
743 }
744 }
745 else if( incgraphic_ok(x) )
746 BackEnd->PrintGraphicInclude(x, save_mark(x), pg - xmk);
747 }
748 *actual_back = xb; *actual_fwd = xf;
749 break;
750
751
752 case SPLIT:
753
754 link = DownDim(x, dim); CountChild(y, link, count);
755 y = FixAndPrintObject(y, xmk, find_max(back(y, dim), xb),
756 find_max(fwd(y, dim), xf), dim, suppress, pg, count,
757 actual_back, actual_fwd);
758 break;
759
760
761 case VCAT:
762 case HCAT:
763
764 if( (type(x) == VCAT) == (dim == ROWM) )
765 {
766 debug6(DGP, DD, "[ FAPO-CAT %s (%s,%s): xmk %s, xb %s, xf %s",
767 Image(type(x)), EchoLength(back(x, dim)), EchoLength(fwd(x, dim)),
768 EchoLength(xmk), EchoLength(xb), EchoLength(xf));
769
770 FirstDefiniteLDN(x, link, prev, jn, xmk, dim, NO_SUPPRESS, pg);
771 if( link != x )
772 {
773
774 /*******************************************************************/
775 /* */
776 /* handle the special case of a 0rt gap at the beginning (left */
777 /* justify) by converting it to 0ie but increasing fwd(prev) to */
778 /* the maximum possible */
779 /* */
780 /*******************************************************************/
781
782 NextDefiniteWithGap(x, link, y, g, jn); /* not LDN since will redo */
783 if( link != x && mode(gap(g)) == TAB_MODE &&
784 units(gap(g)) == AVAIL_UNIT && width(gap(g)) == 0 )
785 {
786 debug2(DGP, DD, " FAPO-CAT converting 0rt (back(x, dim) %s, xb %s)",
787 EchoLength(back(x, dim)), EchoLength(xb));
788 /* NB state change here */
789 fwd(prev, dim) += xb - back(x, dim);
790 back(x, dim) = xb;
791 mode(gap(g)) = EDGE_MODE;
792 units(gap(g)) = FIXED_UNIT;
793 }
794 FirstDefinite(x, link, prev, jn); /* not LDN since already done */
795
796 /*******************************************************************/
797 /* */
798 /* Initialize the following variables: */
799 /* */
800 /* frame_size the total width actually available */
801 /* */
802 /* back_edge where the first element begins */
803 /* */
804 /* inc the adjust increment, used when adjusting gaps */
805 /* */
806 /* mk where the mark of prev is to go */
807 /* */
808 /*******************************************************************/
809
810 frame_size = back(x, dim) + xf;
811 back_edge = xmk - back(x, dim);
812 if( adjust_cat(x) && !suppress )
813 inc = FindAdjustIncrement(x, frame_size, dim);
814 else inc = 0;
815 mk = back_edge + back(prev, dim);
816 debug4(DGP, DD, " FAPO-CAT back_edge %s, mk %s, frame %s, inc %s",
817 EchoLength(back_edge), EchoLength(mk), EchoLength(frame_size),
818 EchoLength(inc));
819
820 /*******************************************************************/
821 /* */
822 /* Fix each element "prev" in turn along the cat operator */
823 /* */
824 /*******************************************************************/
825
826 NextDefiniteWithGapLDN(x, link, y, g, jn, mk, dim, NO_SUPPRESS, pg);
827 while( link != x )
828 {
829 if( mode(gap(g)) == TAB_MODE && units(gap(g)) == AVAIL_UNIT &&
830 width(gap(g))==FR )
831 {
832 /* object is followed by 1rt gap, give it full space to print */
833 debug5(DGP,D," FAPO (a) calling FAPO(%s, %s, %s, max(%s, %s))",
834 Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
835 EchoLength(fwd(prev, dim)), EchoLength(xmk+xf-mk-size(y,dim)));
836 prev = FixAndPrintObject(prev, mk, back(prev, dim),
837 find_max(fwd(prev, dim), xmk+xf-mk - size(y, dim)),
838 dim, NO_SUPPRESS, pg, count, &aback, &afwd);
839 }
840 else
841 {
842 debug5(DGP, DD, " FAPO-CAT (b) calling FAPO(%s, %s, %s, %s+%s)",
843 Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
844 EchoLength(fwd(prev, dim)), EchoLength(inc));
845 prev = FixAndPrintObject(prev, mk, back(prev, dim),
846 fwd(prev, dim) + inc, dim, NO_SUPPRESS, pg, count,&aback,&afwd);
847 }
848 mk += ActualGap(afwd, back(y, dim), fwd(y, dim), &gap(g),
849 frame_size, mk - back_edge);
850 prev = y;
851 NextDefiniteWithGapLDN(x, link, y, g, jn, mk, dim, NO_SUPPRESS, pg);
852 }
853
854 /*******************************************************************/
855 /* */
856 /* At end, fix last element in conformity with "suppress" */
857 /* and set *actual_back and *actual_fwd. */
858 /* */
859 /*******************************************************************/
860
861 if( suppress )
862 {
863 debug4(DGP, DD, " FAPO-CAT (c) calling FAPO(%s, %s, %s, %s)",
864 Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
865 EchoLength(fwd(prev, dim)));
866 prev = FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
867 dim, NO_SUPPRESS, pg, count, &aback, &afwd);
868 }
869 else
870 {
871 debug5(DGP, DD," FAPO-CAT (d) calls FAPO(%s, %s, %s, max(%s, %s))",
872 Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
873 EchoLength(fwd(prev, dim)), EchoLength(xmk + xf - mk));
874 ifdebug(DGP, DD, DebugObject(prev));
875 prev = FixAndPrintObject(prev, mk, back(prev,dim),
876 find_max(fwd(prev, dim), xmk + xf - mk),
877 dim, NO_SUPPRESS, pg, count, &aback, &afwd);
878 }
879 *actual_back = find_max(back(x, dim), xb);
880 *actual_fwd = mk + fwd(prev, dim) - back_edge - *actual_back;
881 debugcond4(DGP, DD, type(x) == HCAT,
882 "HCAT original (%s, %s) to actual (%s, %s)",
883 EchoLength(back(x, dim)), EchoLength(fwd(x, dim)),
884 EchoLength(*actual_back), EchoLength(*actual_fwd));
885 }
886 else *actual_back = xb, *actual_fwd = xf;
887 debug0(DGP, DD, "] FAPO-CAT returning.");
888 }
889 else
890 { OBJECT start_group, zlink, m; BOOLEAN dble_found;
891 FULL_LENGTH b, f, dlen;
892 start_group = nilobj; dble_found = FALSE; dlen = 0;
893 debug0(DGP, DD, " groups beginning.");
894 FirstDefiniteLDN(x, link, y, jn, xmk, dim, NO_SUPPRESS, pg);
895 if( link != x )
896 {
897 /* start first group, with or without join */
898 b = back(y, dim);
899 f = fwd(y, dim);
900 m = y;
901 start_group = link;
902 dble_found = !jn;
903 debug4(DGP, DD, " starting first group %s (%sdbl_found): b %s, f %s",
904 Image(type(y)), dble_found ? "" : "not ",
905 EchoLength(b), EchoLength(f));
906
907 NextDefiniteWithGapLDN(x, link, y, g, jn, xmk, dim, NO_SUPPRESS, pg);
908 while( link != x )
909 {
910 if( !jn )
911 {
912 /* finish off and fix the group ending just before g */
913 debug2(DGP, DD, " finishing group: b = %s, f = %s",
914 EchoLength(b), EchoLength(f));
915 m = FixAndPrintObject(m, xmk+b, b, xf-b, dim,
916 NO_SUPPRESS, pg, count, &aback, &afwd);
917 b = back(m, dim); f = fwd(m, dim);
918 for( zlink = start_group; zlink != link; zlink=NextDown(zlink) )
919 { CountChild(z, zlink, count);
920 if( !is_definite(type(z)) || z == m ) continue;
921 z = FixAndPrintObject(z, xmk + b, b, xf - b, dim,
922 SUPPRESS, pg, count, &aback, &afwd);
923 b = find_max(b, back(z, dim)); f = find_max(f, fwd(z, dim));
924 }
925 dlen = find_max(dlen, b + f);
926 dble_found = TRUE;
927 start_group = nilobj;
928
929 /* start new group */
930 b = back(y, dim);
931 f = fwd(y, dim);
932 m = y;
933 start_group = link;
934 debug2(DGP, DD, " starting group: b = %s, f = %s",
935 EchoLength(b), EchoLength(f));
936 }
937 else
938 {
939 /* continue with current group */
940 b = find_max(b, back(y, dim));
941 f = find_max(f, fwd(y, dim));
942 if( fwd(y, dim) > fwd(m, dim) ) m = y;
943 debug2(DGP, DD, " continuing group: b = %s, f = %s",
944 EchoLength(b), EchoLength(f));
945 }
946
947 NextDefiniteWithGapLDN(x, link, y, g, jn, xmk, dim, NO_SUPPRESS, pg);
948 }
949 assert( start_group != nilobj, "FAPO: final start_group!" );
950
951 if( dble_found || !jn )
952 {
953 /* finish off and fix this last group */
954 debug2(DGP, DD, " finishing last group: b = %s, f = %s",
955 EchoLength(b), EchoLength(f));
956 m = FixAndPrintObject(m, xmk+b, b, xf - b, dim, NO_SUPPRESS, pg,
957 count, &aback, &afwd);
958 b = back(m, dim); f = fwd(m, dim);
959 for( zlink = start_group; zlink != x; zlink = NextDown(zlink) )
960 { CountChild(z, zlink, count);
961 if( !is_definite(type(z)) || z == m ) continue;
962 z = FixAndPrintObject(z, xmk+b, b, xf - b, dim, SUPPRESS, pg,
963 count, &aback, &afwd);
964 b = find_max(b, back(z, dim)); f = find_max(f, fwd(z, dim));
965 }
966 dlen = find_max(dlen, b + f);
967 *actual_back = 0; *actual_fwd = dlen;
968 }
969 else
970 {
971 /* finish off and fix this last and only group */
972 debug2(DGP, DD, " finishing last and only group: b = %s, f = %s",
973 EchoLength(b), EchoLength(f));
974 m = FixAndPrintObject(m, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
975 &b, &f);
976 for( zlink = start_group; zlink != x; zlink = NextDown(zlink) )
977 { CountChild(z, zlink, count);
978 if( !is_definite(type(z)) || z == m ) continue;
979 z = FixAndPrintObject(z, xmk, xb, xf, dim, SUPPRESS, pg, count,
980 &aback, &afwd);
981 b = find_max(b, aback); f = find_max(f, afwd);
982 }
983 *actual_back = b; *actual_fwd = f;
984 }
985 }
986 }
987 break;
988
989
990 case ACAT:
991
992 if( dim == COLM )
993 { BOOLEAN will_adjust, adjusting;
994 FULL_LENGTH actual_size, adjust_indent, frame_size, back_edge;
995 FULL_LENGTH adjust_inc, inc = 0, adjust_sofar = 0;
996 int adjustable_gaps, gaps_sofar = 0;
997 BOOLEAN underlining; int underline_xstart = 0;
998 FONT_NUM underline_font = 0;
999 COLOUR_NUM underline_colour = 0;
1000 TEXTURE_NUM underline_texture = 0;
1001 OBJECT urec, last_bad_gap;
1002
1003
1004 /*********************************************************************/
1005 /* */
1006 /* The first step is to calculate the following values: */
1007 /* */
1008 /* last_bad_gap The rightmost tab gap, or nilobj if none; */
1009 /* */
1010 /* adjustable_gaps the number of gaps suitable for adjustment; */
1011 /* i.e. to the right of the right-most tab gap, */
1012 /* and of non-zero width; */
1013 /* */
1014 /* actual_size the actual size of x without adjustment. */
1015 /* */
1016 /* These are needed when adjusting the line. */
1017 /* */
1018 /*********************************************************************/
1019
1020 FirstDefinite(x, link, y, jn); /* no LDN since this is initial pass */
1021 if( link == x )
1022 {
1023 *actual_back = back(x, dim); *actual_fwd = fwd(x, dim);
1024 FirstDefiniteLDN(x, link, y, jn, xmk, dim, NO_SUPPRESS, pg);
1025 break; /* no definite children, nothing to print */
1026 }
1027
1028 /*** nasty bug finder
1029 { OBJECT ff = y;
1030 debugcond1(DGP, DD, word_equal(ff, "@ReportLayout"),
1031 "FAPO(%s, COLM)", EchoObject(x));
1032 debugcond1(DGP, DD, word_equal(ff, "@ReportLayout"),
1033 " adjust_cat(x) = %s", bool(adjust_cat(x)));
1034 }
1035 ***/
1036
1037 last_bad_gap = nilobj;
1038 adjustable_gaps = 0;
1039 back_edge = xmk - xb;
1040 mk = back_edge + back(y, dim);
1041 frame_size = xb + xf;
1042 prev = y;
1043 NextDefiniteWithGap(x, link, y, g, jn); /* no LDN, initial pass */
1044 while( link != x )
1045 {
1046 save_actual_gap(g) = ActualGap(fwd(prev, dim), back(y, dim),
1047 fwd(y, dim), &gap(g), frame_size, mk - back_edge);
1048 mk += save_actual_gap(g);
1049 if( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
1050 || units(gap(g)) == FRAME_UNIT )
1051 { last_bad_gap = g;
1052 adjustable_gaps = 0;
1053 }
1054 else if( width(gap(g)) > 0 ) adjustable_gaps++;
1055 prev = y;
1056 NextDefiniteWithGap(x, link, y, g, jn); /* no LDN, initial pass */
1057 }
1058 actual_size = mk + fwd(prev, dim) - back_edge;
1059
1060 /*********************************************************************/
1061 /* */
1062 /* It is possible that the line cannot be displayed in any */
1063 /* reasonable way, because the paragraph breaker was forced to */
1064 /* produce an overfull line. In this case, actual_size will */
1065 /* exceed frame_size and there will be no adjustable gaps. The */
1066 /* solution is to horizontally scale the line if possible, or */
1067 /* else to not print it at all. */
1068 /* */
1069 /*********************************************************************/
1070
1071 if( actual_size > frame_size && adjustable_gaps == 0 )
1072 {
1073 /* can't be fixed by adjustment, so scale the line or delete it */
1074 CONSTRAINT c;
1075 SetConstraint(c, 0, frame_size, frame_size);
1076 fwd(x, dim) = actual_size;
1077 debug2(DGP, DD, " oversize, actual_size = %s, frame_size = %s",
1078 EchoLength(actual_size), EchoLength(frame_size));
1079 if( BackEnd->scale_avail && InsertScale(x, &c) )
1080 {
1081 /* the problem has just been fixed, by inserting a @Scale above x */
1082 OBJECT prnt;
1083 Parent(prnt, Up(x));
1084 Child(y, Down(x));
1085 if( actual_size - frame_size < 1 * PT )
1086 {
1087 /* the correction is probably due to roundoff error, and */
1088 /* anyway is too small to print an error message about */
1089 }
1090 else if( Down(x) == LastDown(x) && is_word(type(y)) )
1091 {
1092 Error(23, 3, "word %s horizontally scaled by factor %.2f (too wide for %s paragraph)",
1093 WARN, &fpos(y), string(y), (float) bc(constraint(prnt)) / SF,
1094 EchoLength(frame_size));
1095 }
1096 else
1097 {
1098 Error(23, 4, "%s object horizontally scaled by factor %.2f (too wide for %s paragraph)",
1099 WARN, &fpos(x), EchoLength(size(x, COLM)),
1100 (float) bc(constraint(prnt)) / SF, EchoLength(frame_size));
1101 }
1102 prnt = FixAndPrintObject(prnt, xmk, back(prnt, dim), fwd(prnt, dim), dim,
1103 NO_SUPPRESS, pg, count, &aback, &afwd);
1104 }
1105 else
1106 {
1107 /* fix the problem by refraining from printing the line */
1108 if( size(x, COLM) <= 0 )
1109 Error(23, 5, "oversize object has size 0 or less", INTERN, &fpos(x));
1110 Child(y, Down(x));
1111 if( Down(x) == LastDown(x) && is_word(type(y)) )
1112 { Error(23, 6, "word %s deleted (too wide for %s paragraph)",
1113 WARN, &fpos(y), string(y), EchoLength(frame_size));
1114 }
1115 else
1116 { Error(23, 7, "%s object deleted (too wide for %s paragraph)",
1117 WARN, &fpos(x), EchoLength(size(x, COLM)), EchoLength(frame_size));
1118 }
1119
1120 /* delete and dispose every child of x */
1121 while( Down(x) != x )
1122 DisposeChild(Down(x));
1123 y = MakeWord(WORD, STR_EMPTY, &fpos(x));
1124 Link(x, y);
1125 back(y, COLM) = fwd(y, COLM) = 0;
1126 back(y, ROWM) = fwd(y, ROWM) = 0;
1127 }
1128 }
1129 else
1130 {
1131
1132 /********************************************************************/
1133 /* */
1134 /* The line may be displayed in one of four ways: centred, right- */
1135 /* justified, adjusted, or none of the above (i.e. left justified).*/
1136 /* An overfull line is always adjusted; otherwise, the line will */
1137 /* be centred or right justified if the display style asks for it; */
1138 /* otherwise, the line will be adjusted if adjust_cat(x) == TRUE */
1139 /* (i.e. there is an enclosing @PAdjust) or if the display style is*/
1140 /* DO_ADJUST (meaning that this line is one of a paragraph set in */
1141 /* the adjust or outdent break style, other than the last line); */
1142 /* otherwise, the line is left justified. */
1143 /* */
1144 /* The second step is to decide which of these four cases holds */
1145 /* for this line, and to record the decision in these variables: */
1146 /* */
1147 /* will_adjust TRUE if the adjusted style applies; in this */
1148 /* case, variables adjust_inc and inc will be */
1149 /* set to the appropriate adjustment value; */
1150 /* */
1151 /* adjust_indent If centring or right justification applies, */
1152 /* the indent to produce this, else zero. */
1153 /* */
1154 /* NB adjust_inc may be negative, if the optimal paragraph breaker */
1155 /* has chosen to shrink some gaps. */
1156 /* */
1157 /* NB we are assigning to adjust_cat here; is this a problem? */
1158 /* */
1159 /********************************************************************/
1160
1161 if( actual_size > frame_size )
1162 {
1163 assert( adjustable_gaps > 0, "FAPO: adjustable_gaps!" );
1164 adjust_cat(x) = TRUE;
1165 adjust_indent = 0;
1166 }
1167 else switch( display_style(save_style(x)) )
1168 {
1169 case DO_ADJUST: adjust_cat(x) = TRUE;
1170 adjust_indent = 0;
1171 debug1(DSF, D, "adjust %s", EchoObject(x));
1172 break;
1173
1174 case DISPLAY_CENTRE: adjust_cat(x) = FALSE;
1175 adjust_indent = (frame_size - actual_size)/2;
1176 debug1(DGP, DD, "cdisp %s", EchoObject(x));
1177 break;
1178
1179 case DISPLAY_RIGHT: adjust_cat(x) = FALSE;
1180 adjust_indent = frame_size - actual_size;
1181 debug1(DGP, DD, "rdisp %s", EchoObject(x));
1182 debug1(DSF, D, "rdisp %s", EchoObject(x));
1183 break;
1184
1185 default: /* leave adjust_cat(x) as is */
1186 adjust_indent = 0;
1187 break;
1188 }
1189
1190 debug1(DGP, DD, "ACAT COLM %s", EchoObject(x));
1191 /* EchoStyle(&save_style(x)), EchoObject(x)); */
1192 debug2(DGP, DD, "frame_size = %s, actual_size = %s",
1193 EchoLength(frame_size), EchoLength(actual_size));
1194
1195 if( adjust_cat(x) && adjustable_gaps > 0 )
1196 { will_adjust = TRUE;
1197 adjust_inc = (frame_size - actual_size) / adjustable_gaps;
1198 inc = find_max(adjust_inc, 0);
1199 gaps_sofar = 0; /* number of gaps adjusted so far */
1200 adjust_sofar = 0; /* total width of adjustments so far */
1201 debug2(DGP, DD,"will_adjust: adjustable_gaps = %d, adjust_inc = %s",
1202 adjustable_gaps, EchoLength(adjust_inc));
1203 }
1204 else will_adjust = FALSE;
1205
1206
1207 /********************************************************************/
1208 /* */
1209 /* The third and final step is to traverse x, fixing subobjects. */
1210 /* Variable "adjusting" is true while adjusting is occurring. */
1211 /* */
1212 /********************************************************************/
1213
1214 underlining = FALSE;
1215 adjusting = will_adjust && last_bad_gap == nilobj;
1216 FirstDefiniteLDN(x, link, y, jn, xmk, dim, NO_SUPPRESS, pg);
1217 prev = y;
1218 mk = xmk - back(x, dim) + back(y, dim) + adjust_indent;
1219 NextDefiniteWithGapLDN(x, link, y, g, jn, mk, dim, NO_SUPPRESS, pg);
1220 while( link != x )
1221 {
1222 /* check for underlining */
1223 if( underline(prev) == UNDER_ON )
1224 {
1225 debug3(DGP, DD, " FAPO/ACAT1 underline() := %s for %s %s",
1226 bool(FALSE), Image(type(prev)), EchoObject(prev));
1227 if( !underlining )
1228 {
1229 /* underlining begins here */
1230 underlining = TRUE;
1231 debug2(DGP, DD, "underlining begins at %s %s",
1232 Image(type(prev)), EchoObject(prev));
1233 if( is_word(type(prev)) )
1234 {
1235 underline_font = word_font(prev);
1236 underline_colour = word_underline_colour(prev);
1237 underline_texture = word_texture(prev);
1238 }
1239 else
1240 {
1241 underline_font = font(save_style(x));
1242 underline_colour = underline_colour(save_style(x));
1243 underline_texture = texture(save_style(x));
1244 }
1245 underline_xstart = mk - back(prev, dim);
1246 }
1247 if( underline(g) == UNDER_OFF )
1248 {
1249 /* underlining ends here */
1250 debug2(DGP, DD, "underlining ends at %s %s",
1251 Image(type(prev)), EchoObject(prev));
1252 New(urec, UNDER_REC);
1253 back(urec, COLM) = underline_xstart;
1254 fwd(urec, COLM) = mk + fwd(prev, dim);
1255 word_font(urec) = underline_font;
1256 word_underline_colour(urec) = underline_colour;
1257 word_texture(urec) = underline_texture;
1258 underlining = FALSE;
1259 Link(NextDown(Up(prev)), urec);
1260 }
1261 }
1262
1263 /* fix previous definite now we know it is not the last one */
1264 if( adjusting && width(gap(g)) > 0 )
1265 { int tmp;
1266
1267 prev = FixAndPrintObject(prev, mk, back(prev, dim),
1268 fwd(prev, dim) + inc, dim, NO_SUPPRESS, pg, count,&aback,&afwd);
1269 gaps_sofar++;
1270 tmp = ((frame_size - actual_size) * gaps_sofar) / adjustable_gaps;
1271 mk += save_actual_gap(g) + (tmp - adjust_sofar);
1272 adjust_sofar = tmp;
1273 }
1274 else
1275 {
1276 prev = FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev,dim),
1277 dim, NO_SUPPRESS, pg, count, &aback, &afwd);
1278
1279 mk += save_actual_gap(g);
1280 }
1281 prev = y;
1282
1283 /* commence adjustment if required */
1284 if( !adjusting && will_adjust && g == last_bad_gap )
1285 adjusting = TRUE;
1286
1287 NextDefiniteWithGapLDN(x, link, y, g, jn, mk, dim, NO_SUPPRESS, pg);
1288 }
1289
1290 /* check for underlining */
1291 debugcond3(DGP, DD, underline(prev) == UNDER_UNDEF,
1292 " underlining is UNDER_UNDEF in %s: %s %s in para:",
1293 EchoFilePos(&fpos(prev)), Image(type(prev)), EchoObject(prev));
1294 debugcond1(DGP, DD, underline(prev)==UNDER_UNDEF, "%s",EchoObject(x));
1295 assert( underline(prev) == UNDER_OFF || underline(prev) == UNDER_ON,
1296 "FixAndPrint: underline(prev)!" );
1297 if( underline(prev) == UNDER_ON )
1298 {
1299 debug3(DGP, DD, " FAPO/ACAT1 underline() := %s for %s %s",
1300 bool(FALSE), Image(type(prev)), EchoObject(prev));
1301 if( !underlining )
1302 {
1303 /* underlining begins here */
1304 debug2(DGP, DD, "underlining begins at %s %s",
1305 Image(type(prev)), EchoObject(prev));
1306 underlining = TRUE;
1307 if( is_word(type(prev)) )
1308 {
1309 underline_font = word_font(prev);
1310 underline_colour = word_underline_colour(prev);
1311 underline_texture = word_texture(prev);
1312 }
1313 else
1314 {
1315 underline_font = font(save_style(x));
1316 underline_colour = underline_colour(save_style(x));
1317 underline_texture = texture(save_style(x));
1318 }
1319 underline_xstart = mk - back(prev, dim);
1320 }
1321
1322 /* underlining must end here */
1323 debug2(DGP, DD, "underlining ends at %s %s",
1324 Image(type(prev)), EchoObject(prev));
1325 New(urec, UNDER_REC);
1326 back(urec, COLM) = underline_xstart;
1327 fwd(urec, COLM) = mk + fwd(prev, dim);
1328 word_font(urec) = underline_font;
1329 word_underline_colour(urec) = underline_colour;
1330 word_texture(urec) = underline_texture;
1331 underlining = FALSE;
1332 Link(NextDown(Up(prev)), urec);
1333 }
1334
1335 /* fix the last definite subobject, prev, which must exist */
1336 prev = FixAndPrintObject(prev, mk, back(prev, dim),
1337 frame_size - (mk - xmk) - back(x, dim),
1338 dim, NO_SUPPRESS, pg, count, &aback, &afwd);
1339
1340 }
1341 }
1342 else
1343 {
1344 debug1(DGP, DD, "ACAT ROWM %s", EchoObject(x));
1345 for( link = Down(x); link != x; link = NextDown(link) )
1346 { Child(y, link);
1347 if( !is_definite(type(y)) && type(y) != LINK_DEST_NULL )
1348 {
1349 if( type(y) == UNDER_REC ) /* generate an underline now */
1350 { BackEnd->PrintUnderline(word_font(y),word_underline_colour(y),
1351 word_texture(y), back(y, COLM), fwd(y, COLM), pg - xmk);
1352 link = PrevDown(link); /* remove all trace of underlining */
1353 DisposeChild(Up(y)); /* in case we print this again */
1354 }
1355 continue;
1356 }
1357 y = FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count,
1358 &aback, &afwd);
1359 }
1360 }
1361 *actual_back = xb; *actual_fwd = xf;
1362 break;
1363
1364
1365 case COL_THR:
1366 case ROW_THR:
1367
1368 assert( (type(x) == COL_THR) == (dim == COLM), "FixAndPrintObject: thr!" );
1369 for( link = Down(x), uplink = Up(x), i = 1;
1370 link != x && uplink != x && i < count;
1371 link = NextDown(link), uplink = NextUp(uplink), i++ );
1372 assert( link != x && uplink != x, "FixAndPrintObject: link or uplink!" );
1373 CountChild(y, link, count);
1374 debug7(DGP, DD, " fapo of %s (%s,%s) child %d %s (%s,%s)",
1375 Image(type(x)),
1376 EchoLength(back(x, dim)), EchoLength(fwd(x, dim)),
1377 i, Image(type(y)), EchoLength(back(y, dim)), EchoLength(fwd(y, dim)));
1378
1379 /* This line seems to have been an optimization. It won't
1380 * work if we are inside a running header, since subsequent
1381 * passes will have forgotten the thread. JeffK 13/11/02
1382 MoveLink(uplink, link, CHILD); DeleteLink(link);
1383 */
1384
1385 assert( type(y) != GAP_OBJ, "FAPO: THR!");
1386
1387 if( thr_state(x) != FINALSIZE )
1388 { back(x, dim) = xb; fwd(x, dim) = xf;
1389 thr_state(x) = FINALSIZE;
1390 }
1391
1392 y = FixAndPrintObject(y, xmk, back(x, dim), fwd(x, dim), dim,
1393 NO_SUPPRESS, pg, count, &aback, &afwd);
1394 *actual_back = xb; *actual_fwd = xf;
1395 /* if( Up(x) == x ) Dispose(x); */
1396 break;
1397
1398 /* convert everyone to FIXED_COL_THR or FIXED_ROW_THR as appropriate */
1399 /* *** old code
1400 if( thr_state(x) == FINALSIZE )
1401 debug1(DGP, DD, "thr_state(%d)", (int) x);
1402 assert(thr_state(x) != FINALSIZE, "FAPO/COL_THR: thr_state(x)!");
1403 ifdebug(DGP, DD,
1404 link = Down(x);
1405 uplink = Up(x);
1406 while( link != x && uplink != x )
1407 {
1408 Parent(tmp, uplink);
1409 debug1(DGP, DD, "parnt: %s", EchoObject(tmp));
1410 Child(tmp, link);
1411 debug1(DGP, DD, "child: %s", EchoObject(tmp));
1412 link = NextDown(link);
1413 uplink = NextUp(uplink);
1414 }
1415 while( uplink != x )
1416 { Parent(tmp, uplink);
1417 debug1(DGP, DD, "extra parnt: %s", EchoObject(tmp));
1418 uplink = NextUp(uplink);
1419 }
1420 while( link != x )
1421 { Child(tmp, link);
1422 debug1(DGP, DD, "extra child: %s", EchoObject(tmp));
1423 link = NextDown(link);
1424 }
1425 )
1426 i = 1; res = nilobj;
1427 while( Down(x) != x && Up(x) != x )
1428 {
1429 New(fixed_thr, type(x) == COL_THR ? FIXED_COL_THR : FIXED_ROW_THR);
1430 MoveLink(Up(x), fixed_thr, CHILD);
1431 MoveLink(Down(x), fixed_thr, PARENT);
1432 back(fixed_thr, dim) = xb;
1433 fwd(fixed_thr, dim) = xf;
1434 if( count == i )
1435 res = fixed_thr;
1436 i++;
1437 }
1438 if( Up(x) != x || Down(x) != x )
1439 {
1440 debug2(DGP, DD, "links problem at %s %d:", Image(type(x)), (int) x);
1441 if( Up(x) != x )
1442 {
1443 Parent(tmp, Up(x));
1444 debug1(DGP, DD, "first parent is %s", EchoObject(tmp));
1445 }
1446 if( Down(x) != x )
1447 {
1448 Child(tmp, Down(x));
1449 debug1(DGP, DD, "first child is %s", EchoObject(tmp));
1450 }
1451 }
1452 assert( Up(x) == x && Down(x) == x, "FAPO/COL_THR: x links!" );
1453 Dispose(x);
1454 assert(res != nilobj, "FixAndPrintObject: COL_THR res!");
1455 x = res;
1456 *** */
1457 /* NB NO BREAK! */
1458
1459
1460 /* ***
1461 case FIXED_COL_THR:
1462 case FIXED_ROW_THR:
1463
1464 assert( (type(x) == FIXED_COL_THR) == (dim == COLM),
1465 "FixAndPrintObject: fixed_thr!" );
1466 CountChild(y, Down(x), count);
1467 y = FixAndPrintObject(y, xmk, back(x, dim), fwd(x, dim), dim,
1468 NO_SUPPRESS, pg, count, &aback, &afwd);
1469 *actual_back = back(x, dim); *actual_fwd = fwd(x, dim);
1470 break;
1471 *** */
1472
1473
1474 case BEGIN_HEADER:
1475 case END_HEADER:
1476 case SET_HEADER:
1477 case CLEAR_HEADER:
1478
1479 if( dim == COLM )
1480 Error(23, 8, "%s symbol ignored (out of place)", WARN, &fpos(x),
1481 Image(type(x)));
1482 break;
1483
1484
1485 default:
1486
1487 assert1(FALSE, "FixAndPrintObject:", Image(type(x)));
1488 break;
1489
1490
1491 } /* end switch */
1492 debug2(DGP, DD, "] FixAndPrintObject returning (actual %s,%s).",
1493 EchoLength(*actual_back), EchoLength(*actual_fwd));
1494 return res;
1495 } /* end FixAndPrintObject */
1496