home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / lout2.lzh / LOUT2 / z23.c < prev    next >
Text File  |  1994-01-23  |  28KB  |  750 lines

  1. /*@z23.c:Galley Printer:ScaleFactor()@****************************************/
  2. /*                                                                           */
  3. /*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  4. /*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  5. /*                                                                           */
  6. /*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  7. /*  Basser Department of Computer Science                                    */
  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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  24. /*                                                                           */
  25. /*  FILE:         z23.c                                                      */
  26. /*  MODULE:       Galley Printer                                             */
  27. /*  EXTERNS:      FixAndPrintObject()                                        */
  28. /*                                                                           */
  29. /*****************************************************************************/
  30. #include "externs"
  31. #define    NO_SUPPRESS    FALSE
  32. #define    SUPPRESS    TRUE
  33. #define    ALL_ADJUST    2
  34. #define    LAST_ADJUST    1
  35. #define    ALL_ADJUST    2
  36.  
  37. #define CountChild(y, link, i)                        \
  38. for( y=pred(link, PARENT), i=1; type(y)==LINK;  y = pred(y, PARENT), i++ )
  39.  
  40.  
  41. /*****************************************************************************/
  42. /*                                                                           */
  43. /*  static float ScaleFactor(avail_size, inner_size)                         */
  44. /*                                                                           */
  45. /*  Return the scale factor for this scaling, or 0 if impossible.            */
  46. /*                                                                           */
  47. /*****************************************************************************/
  48.  
  49. static float ScaleFactor(avail_size, inner_size)
  50. LENGTH avail_size, inner_size;
  51. { float scale_factor;
  52.   scale_factor = avail_size <= 0 ? 0 :
  53.          inner_size <= 0 ? 0 : (float) avail_size / inner_size;
  54.   return scale_factor;
  55. }
  56.  
  57.  
  58. /*@::FindAdjustIncrement()@***************************************************/
  59. /*                                                                           */
  60. /*  static LENGTH FindAdjustIncrement(x, frame_size, dim)                    */
  61. /*                                                                           */
  62. /*  Find the amount by which to increase the width of the subobjects of      */
  63. /*  concatenation object x so that it is adjusted to fill size frame_size.   */
  64. /*                                                                           */
  65. /*****************************************************************************/
  66.  
  67. static LENGTH FindAdjustIncrement(x, frame_size, dim)
  68. OBJECT x;  LENGTH frame_size;  int dim;
  69. { OBJECT y, link, prev, g;
  70.   int adjustable_gaps;
  71.   LENGTH inc, mk, actual_size;
  72.  
  73.   debug2(DGP, D, "FindAdjustIncrement(x, %s, %s)",
  74.     EchoLength(frame_size), dimen(dim));
  75.   FirstDefinite(x, link, prev);
  76.   if( link != x )
  77.   { adjustable_gaps = 0;
  78.     mk = back(prev, dim);
  79.     NextDefiniteWithGap(x, link, y, g);
  80.     while( link != x )
  81.     { if ( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
  82.                     || units(gap(g)) == FRAME_UNIT )
  83.       {    debug0(DGP, D, "FindAdjustIncrement returning 0 (tab gap)");
  84.     return 0;
  85.       }
  86.       mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
  87.         frame_size, mk);
  88.       prev = y;
  89.       adjustable_gaps++;
  90.       NextDefiniteWithGap(x, link, y, g);
  91.     }
  92.     actual_size = mk + fwd(prev, dim);
  93.     debug2(DGP, DD, "  actual_size = %s, adjustable_gaps = %d",
  94.     EchoLength(actual_size), adjustable_gaps);
  95.     inc = adjustable_gaps==0 ? 0 : (frame_size - actual_size) / adjustable_gaps;
  96.   }
  97.   else inc = 0;
  98.   debug1(DGP, D, "FindAdjustIncrement returning %s", EchoLength(inc));
  99.   return inc;
  100. } /* end FindAdjustIncrement */
  101.  
  102.  
  103. /*@::FixAndPrintObject()@*****************************************************/
  104. /*                                                                           */
  105. /*  FixAndPrintObject(x, xmk, xb, xf, dim, adjust, suppress, padj, pg,count) */
  106. /*                                                                           */
  107. /*  Fix the absolute position of object x in dimension dim, in such a way    */
  108. /*  that the principal mark of x has coordinate xmk, and x has actual size   */
  109. /*  (xb, xf), where xb >= back(x, dim) and xf >= fwd(x, dim).                */
  110. /*                                                                           */
  111. /*  Actually, in the case where x includes an object lying on a thread       */
  112. /*  leading outside x, the final size of x may be different.  Because        */
  113. /*  of this, the procedure sets back(x, dim) and fwd(x, dim) to the actual   */
  114. /*  size of x upon return.  The caller assumes that x will exactly occupy    */
  115. /*  this space back(x, dim), fwd(x, dim).                                    */
  116. /*                                                                           */
  117. /*  If x does not fill the forward part of the space allocated to it, the    */
  118. /*  adjust parameter determines what, if anything, to do about this.  The    */
  119. /*  two possible values of this parameter are:                               */
  120. /*                                                                           */
  121. /*    LAST_ADJUST        Adjust x to fill the forward space available to     */
  122. /*                       it, by adjusting the last component if x is a       */
  123. /*                       CAT object, or adjusting the child otherwise.       */
  124. /*                                                                           */
  125. /*    ALL_ADJUST         Adjust x to fill the forward space available to     */
  126. /*                       it, by adjusting all the components if x is a       */
  127. /*                       CAT object, or adjusting the child otherwise.       */
  128. /*                                                                           */
  129. /*  The suppress parameter is true if a temporary suppression of adjustment  */
  130. /*  is in effect (because a neighbouring adjustment has already been done).  */
  131. /*                                                                           */
  132. /*  The padj parameter is analogous to the adjust parameter, but it          */
  133. /*  applies only to & adjustment, not to | or / adjustment.                  */
  134. /*                                                                           */
  135. /*  If dim == COL, the coordinate information is merely stored; but if       */
  136. /*  dim == ROW, it is used to generate PostScript for printing x.            */
  137. /*                                                                           */
  138. /*  Parameter pg records the height of the current page.  This is used       */
  139. /*  to correct for the fact that Lout places its origin is at the top left,  */
  140. /*  while PostScript places its origin at the bottom left.  This correction  */
  141. /*  cannot be made by transforming user space.                               */
  142. /*                                                                           */
  143. /*  x is child number count of its parent (used by COL_THR and ROW_THR only) */
  144. /*                                                                           */
  145. /*****************************************************************************/
  146.  
  147. FixAndPrintObject(x, xmk, xb, xf, dim, adjust, suppress, padj, pg, count)
  148. OBJECT x;  LENGTH xmk, xb, xf; int dim, adjust;  BOOLEAN suppress;
  149. int padj;  LENGTH pg;  int count;
  150. { OBJECT y, link, prev, g, uplink, z;
  151.   LENGTH mk, frame_size, back_edge, yb, yf, inc;
  152.   int i; float scale_factor;
  153.   debug8(DGP, D, "[ FixAndPrintObject(%s, %s, %s,%s, %s, %s, %s, %s, pg ), x =",
  154.     Image(type(x)), EchoLength(xmk), EchoLength(xb), EchoLength(xf), dimen(dim),
  155.     (adjust == LAST_ADJUST ? "last_adjust" : "all_adjust"),
  156.     (suppress == SUPPRESS ? "suppress" : "no_suppress"),
  157.     (padj   == LAST_ADJUST ? "last_adjust" : "all_adjust"));
  158.   ifdebug(DGP, DD, DebugObject(x));
  159.  
  160.   switch( type(x) )
  161.   {
  162.  
  163.     case CLOSURE:
  164.     case NULL_CLOS:
  165.     case CROSS:
  166.     
  167.       back(x, dim) = xb;  fwd(x, dim) = xf;
  168.       break;
  169.  
  170.  
  171.     case WORD:
  172.     case QWORD:
  173.     
  174.       if( dim == COL )  word_save_mark(x) = xmk;
  175.       else if( string(x)[0] != '\0' )  PrintWord(x, word_save_mark(x), pg-xmk);
  176.       back(x, dim) = xb;  fwd(x, dim) = xf;
  177.       break;
  178.  
  179.  
  180.     case WIDE:
  181.     case HIGH:
  182.     
  183.       CountChild(y, Down(x), count);
  184.       if( (dim == COL) == (type(x) == WIDE) )
  185.       { yf = bfc(constraint(x)) - back(y, dim);
  186.         FixAndPrintObject(y, xmk, back(y,dim), yf, dim, LAST_ADJUST,
  187.         NO_SUPPRESS, padj, pg, count);
  188.         back(x, dim) = xb;  fwd(x, dim) = xf;
  189.       }
  190.       else
  191.       {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress,
  192.       padj, pg, count);
  193.     back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  194.       }
  195.       break;
  196.  
  197.  
  198.     case HCONTRACT:
  199.     case VCONTRACT:
  200.     
  201.       CountChild(y, Down(x), count);
  202.       if( (dim == COL) == (type(x) == HCONTRACT) )
  203.       {    FixAndPrintObject(y, xmk, back(y,dim), fwd(y,dim), dim, LAST_ADJUST,
  204.       NO_SUPPRESS, padj, pg, count);
  205.         back(x, dim) = xb;  fwd(x, dim) = xf;
  206.       }
  207.       else
  208.       {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress, padj,pg,count);
  209.         back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  210.       }
  211.       break;
  212.  
  213.  
  214.     case ONE_COL:
  215.     case ONE_ROW:
  216.     case HEXPAND:
  217.     case VEXPAND:
  218.     
  219.       CountChild(y, Down(x), count);
  220.       if( (dim == COL) == (type(x) == ONE_COL || type(x) == HEXPAND) )
  221.       { FixAndPrintObject(y, xmk, xb, xf, dim, LAST_ADJUST,
  222.         NO_SUPPRESS, padj, pg, count);
  223.         back(x, dim) = xb;  fwd(x, dim) = xf;
  224.       }
  225.       else
  226.       {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress, padj,pg,count);
  227.     back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  228.       }
  229.       break;
  230.  
  231.  
  232.     case PADJUST:
  233.     
  234.       CountChild(y, Down(x), count);
  235.       FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress,
  236.     ALL_ADJUST, pg, count);
  237.       back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  238.       break;
  239.  
  240.  
  241.     case HADJUST:
  242.     case VADJUST:
  243.     
  244.       CountChild(y, Down(x), count);
  245.       if( (dim == COL) == (type(x) == HADJUST) )
  246.       {    FixAndPrintObject(y, xmk, xb, xf, dim, ALL_ADJUST, suppress,
  247.       padj, pg, count);
  248.         back(x, dim) = xb;  fwd(x, dim) = xf;
  249.       }
  250.       else
  251.       {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress,
  252.       padj, pg, count);
  253.     back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  254.       }
  255.       break;
  256.  
  257.  
  258.     case VSCALE:
  259.  
  260.       debug0(DRS, D, "FixAndPrintObject at VSCALE");
  261.       CountChild(y, Down(x), count);
  262.       if( dim == COL )
  263.       {    FixAndPrintObject(y, xmk, xb, xf, dim, LAST_ADJUST, NO_SUPPRESS,
  264.         padj,pg,count);
  265.       }
  266.       else if( (scale_factor = ScaleFactor(xb+xf, size(y, ROW))) > 0 )
  267.       {    SaveGraphicState();
  268.     CoordTranslate(0, pg - (xmk-xb + (LENGTH) (back(y, ROW)*scale_factor)));
  269.     CoordScale(1.0, scale_factor);
  270.         FixAndPrintObject(y, 0, back(y, ROW), fwd(y, ROW), dim, LAST_ADJUST,
  271.         NO_SUPPRESS, padj, 0, count);
  272.     RestoreGraphicState();
  273.       }
  274.       else if( !is_word(type(y)) || string(y)[0] != '\0' )
  275.       {    Error(WARN, &fpos(x), "object deleted: cannot %s", KW_VSCALE);
  276.       }
  277.       back(x, dim) = xb;  fwd(x, dim) = xf;
  278.       break;
  279.  
  280.  
  281.     case HSCALE:
  282.     
  283.       debug0(DRS, DD, "FixAndPrintObject at HSCALE");
  284.       CountChild(y, Down(x), count);
  285.       if( dim == COL )
  286.       {    save_mark(x) = xmk;
  287.     bc(constraint(x)) = xb;
  288.     fc(constraint(x)) = xf;
  289.         if( (scale_factor = ScaleFactor(xb+xf, size(y, COL))) > 0 )
  290.       FixAndPrintObject(y, 0, back(y, COL), fwd(y, COL), dim, LAST_ADJUST,
  291.         NO_SUPPRESS, LAST_ADJUST, pg, count);
  292.         else if( !is_word(type(y)) || string(y)[0] != '\0' )
  293.       Error(WARN, &fpos(y), "object deleted: cannot %s", KW_HSCALE);
  294.       }
  295.       else if( (scale_factor =
  296.     ScaleFactor(bc(constraint(x))+fc(constraint(x)), size(y, COL))) > 0 )
  297.       {    SaveGraphicState();
  298.     CoordTranslate(save_mark(x) - bc(constraint(x))
  299.        + (LENGTH) (back(y, COL)*scale_factor), 0);
  300.     CoordScale(scale_factor, 1.0);
  301.         FixAndPrintObject(y, xmk, xb, xf, dim, LAST_ADJUST,
  302.         NO_SUPPRESS, padj, pg, count);
  303.     RestoreGraphicState();
  304.       }
  305.       back(x, dim) = xb;  fwd(x, dim) = xf;
  306.       break;
  307.  
  308.  
  309.     case SCALE:
  310.  
  311.       CountChild(y, Down(x), count);
  312.       if( dim == COL )
  313.       {
  314.     assert( bc(constraint(x)) > 0, "FAPO: horizontal scale factor!" );
  315.     save_mark(x) = xmk;
  316.     yb = xb * SF / bc(constraint(x));
  317.     yf = xf * SF / bc(constraint(x));
  318.         FixAndPrintObject(y, 0, yb, yf, dim, LAST_ADJUST, NO_SUPPRESS,
  319.         padj, pg, count);
  320.       }
  321.       else
  322.       {
  323.     assert( fc(constraint(x)) > 0, "FAPO: vertical scale factor!" );
  324.     yb = xb * SF / fc(constraint(x));
  325.     yf = xf * SF / fc(constraint(x));
  326.     SaveGraphicState();
  327.     CoordTranslate(save_mark(x), pg - xmk);
  328.     CoordScale( (float) bc(constraint(x))/SF, (float) fc(constraint(x))/SF);
  329.         FixAndPrintObject(y, 0, yb, yf, dim, LAST_ADJUST, NO_SUPPRESS,
  330.         padj,0,count);
  331.     RestoreGraphicState();
  332.       }
  333.       back(x, dim) = xb;  fwd(x, dim) = xf;
  334.       break;
  335.  
  336.  
  337.     case ROTATE:
  338.     
  339.       CountChild(y, Down(x), count);
  340.       if( dim == COL )
  341.       {    save_mark(x) = xmk;
  342.     back(x, dim) = xb;
  343.     fwd(x, dim)  = xf;
  344.       }
  345.       else
  346.       {
  347.     CONSTRAINT colc, rowc, yc;
  348.     back(x, dim) = xb;
  349.     fwd(x, dim)  = xf;
  350.     SetConstraint(colc, back(x,COL), MAX_LEN, fwd(x,COL));
  351.     SetConstraint(rowc, back(x,ROW), MAX_LEN, fwd(x,ROW));
  352.     RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc, COL);
  353.     FixAndPrintObject(y, 0, bc(yc), fc(yc), COL, LAST_ADJUST,
  354.         NO_SUPPRESS, padj, pg, count);
  355.     SaveGraphicState();
  356.     CoordTranslate(save_mark(x), pg - xmk);
  357.     CoordRotate(sparec(constraint(x)));
  358.     RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc, ROW);
  359.     FixAndPrintObject(y, 0, bc(yc), fc(yc), ROW, LAST_ADJUST,
  360.         NO_SUPPRESS, padj, 0, count);
  361.     RestoreGraphicState();
  362.       }
  363.       back(x, dim) = xb;  fwd(x, dim) = xf;
  364.       break;
  365.  
  366.  
  367.     case GRAPHIC:
  368.     
  369.       CountChild(y, LastDown(x), count);
  370.       if( dim == COL )
  371.       {
  372.     back(x, dim) = xb;
  373.     fwd(x, dim)  = xf;
  374.     debug2(DGP, DD, "GRAPHIC COL storing size %s, %s",
  375.       EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
  376.     save_mark(x) = xmk - back(x, COL);
  377.         FixAndPrintObject(y, xb, xb, xf, dim, LAST_ADJUST,
  378.         NO_SUPPRESS, padj, pg, count);
  379.       }
  380.       else
  381.       { OBJECT tmp, pre, post;
  382.         Child(tmp, Down(x));
  383.         if( type(tmp) == VCAT )
  384.         { Child(pre, Down(tmp));
  385.           Child(post, LastDown(tmp));
  386.         }
  387.         else pre = tmp, post = nil;
  388.     back(x, dim) = xb;
  389.     fwd(x, dim)  = xf;
  390.         SaveGraphicState();
  391.         CoordTranslate(save_mark(x), pg - (xmk + fwd(x, ROW)));
  392.     debug4(DGP, DD, "GRAPHIC ROW calling %s,%s %s,%s",
  393.       EchoLength(back(x, COL)), EchoLength(fwd(x, COL)),
  394.       EchoLength(back(x, ROW)), EchoLength(fwd(x, ROW)));
  395.         DefineGraphicNames(x);
  396.         SaveGraphicState();
  397.         PrintGraphicObject(pre);
  398.         RestoreGraphicState();
  399.         FixAndPrintObject(y, xb, xb, xf, dim, LAST_ADJUST,
  400.         NO_SUPPRESS, padj, xb + xf, count);
  401.         if( post != nil )  PrintGraphicObject(post);
  402.         RestoreGraphicState();
  403.       }
  404.       back(x, dim) = xb;  fwd(x, dim) = xf;
  405.       break;
  406.  
  407.  
  408.     case INCGRAPHIC:
  409.     case SINCGRAPHIC:
  410.  
  411.       CountChild(y, Down(x), count);
  412.       if( dim == COL )
  413.       {    save_mark(x) = xmk;
  414.       }
  415.       else if( sparec(constraint(x)) )
  416.       {
  417.     PrintGraphicInclude(x, save_mark(x), pg - xmk);
  418.       }
  419.       back(x, dim) = xb;  fwd(x, dim) = xf;
  420.       break;
  421.  
  422.  
  423.     case SPLIT:
  424.     
  425.       link = DownDim(x, dim);  CountChild(y, link, count);
  426.       FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress, padj, pg, count);
  427.       back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  428.       break;
  429.  
  430.  
  431.     case VCAT:
  432.     case HCAT:
  433.  
  434.       if( (type(x) == VCAT) == (dim == ROW) )
  435.       { 
  436.     /* find adjustment increment if required */
  437.     frame_size = xb + xf;
  438.     if( adjust == ALL_ADJUST && !suppress )
  439.       inc = FindAdjustIncrement(x, frame_size, dim);
  440.     else inc = 0;
  441.  
  442.     FirstDefinite(x, link, prev);
  443.     if( link != x )
  444.     { back_edge = xmk - back(x, dim);
  445.       mk = back_edge + back(prev, dim);
  446.       NextDefiniteWithGap(x, link, y, g);
  447.       while( link != x )
  448.       {
  449.         FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim) + inc,
  450.           dim, adjust, NO_SUPPRESS, padj, pg, count);
  451.         /* NB fwd(prev, dim) may be changed by the call to FAPO */
  452.         mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
  453.             frame_size, mk - back_edge);
  454.         prev = y;
  455.         NextDefiniteWithGap(x, link, y, g);
  456.       }
  457.       if( suppress )
  458.         FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
  459.           dim, adjust, NO_SUPPRESS, padj, pg, count);
  460.       else
  461.         FixAndPrintObject(prev, mk, back(prev,dim),
  462.           max(fwd(prev, dim), back_edge+frame_size-mk),
  463.           dim, adjust, NO_SUPPRESS, padj, pg, count);
  464.       back(x, dim) = max(back(x, dim), xb);
  465.       fwd(x, dim) = mk + fwd(prev, dim) - back_edge - back(x, dim);
  466.     }
  467.     else back(x, dim) = xb, fwd(x, dim) = xf;
  468.       }
  469.       else
  470.       { OBJECT start_group, zlink, m;  BOOLEAN dble_found;  LENGTH b, f, dlen;
  471.     start_group = nil;  dble_found = FALSE;  dlen = 0;
  472.     debug0(DGP, DD, "  groups beginning.");
  473.     for( link = Down(x);  link != x;  link = NextDown(link) )
  474.     {
  475.       Child(y, link);
  476.       debug1(DGP, DD, "  examining %s", EchoObject(y));
  477.       if( is_index(type(y)) )  continue;
  478.       if( type(y) == GAP_OBJ )
  479.       { 
  480.         assert( start_group != nil, "FAPO: start_group!" );
  481.         if( !join(gap(y)) )
  482.         { 
  483.           /* finish off and fix this group */
  484.           debug2(DGP, DD, "  finishing group: b = %s, f = %s",
  485.             EchoLength(b), EchoLength(f));
  486.           FixAndPrintObject(m, xmk+b, b, xf-b, dim, adjust,
  487.               NO_SUPPRESS, padj, pg, count);
  488.           b = back(m, dim);  f = fwd(m, dim);
  489.           for( zlink = start_group;  zlink != link;  zlink=NextDown(zlink) )
  490.           {    CountChild(z, zlink, count);
  491.         if( !is_definite(type(z)) || z == m )  continue;
  492.         FixAndPrintObject(z, xmk + b, b, xf - b, dim,
  493.               adjust, SUPPRESS, padj, pg, count);
  494.         b = max(b, back(z, dim));  f = max(f, fwd(z, dim));
  495.           }
  496.           dlen = max(dlen, b + f);
  497.           dble_found = TRUE;
  498.           start_group = nil;
  499.         }
  500.       }
  501.       else if( start_group == nil )
  502.       {
  503.         /* start new group */
  504.         b = back(y, dim);
  505.         f = fwd(y, dim);
  506.         m = y;
  507.         start_group = link;
  508.         debug2(DGP, DD, "  starting group: b = %s, f = %s",
  509.           EchoLength(b), EchoLength(f));
  510.       }
  511.       else
  512.       {
  513.         /* continue with current group */
  514.         b = max(b, back(y, dim));
  515.         f = max(f, fwd(y, dim));
  516.         if( fwd(y, dim) > fwd(m, dim) )  m = y;
  517.         debug2(DGP, DD, "  continuing group: b = %s, f = %s",
  518.           EchoLength(b), EchoLength(f));
  519.       }
  520.     }
  521.     assert( start_group != nil, "FAPO: final start_group!" );
  522.  
  523.     if( dble_found )
  524.     {
  525.       /* finish off and fix this last group */
  526.       debug2(DGP, DD, "  finishing last group: b = %s, f = %s",
  527.           EchoLength(b), EchoLength(f));
  528.       FixAndPrintObject(m, xmk + b, b, xf - b, dim, adjust,
  529.         NO_SUPPRESS, padj, pg, count);
  530.       b = back(m, dim);  f = fwd(m, dim);
  531.       for( zlink = start_group;  zlink != link;  zlink = NextDown(zlink) )
  532.       { CountChild(z, zlink, count);
  533.         if( !is_definite(type(z)) || z == m )  continue;
  534.         FixAndPrintObject(z, xmk + b, b, xf - b, dim, adjust,
  535.         SUPPRESS, padj, pg, count);
  536.         b = max(b, back(z, dim));  f = max(f, fwd(z, dim));
  537.       }
  538.       dlen = max(dlen, b + f);
  539.       back(x, dim) = 0;  fwd(x, dim) = dlen;
  540.     }
  541.     else
  542.     {
  543.       /* finish off and fix this last and only group */
  544.       debug2(DGP, DD, "  finishing last and only group: b = %s, f = %s",
  545.           EchoLength(b), EchoLength(f));
  546.       FixAndPrintObject(m, xmk, xb, xf, dim, adjust,
  547.          NO_SUPPRESS, padj, pg, count);
  548.       b = back(m, dim);  f = fwd(m, dim);
  549.       for( zlink = start_group;  zlink != link;  zlink = NextDown(zlink) )
  550.       { CountChild(z, zlink, count);
  551.         if( !is_definite(type(z)) || z == m )  continue;
  552.         FixAndPrintObject(z, xmk, xb, xf, dim, adjust,
  553.         SUPPRESS, padj, pg, count);
  554.         b = max(b, back(z, dim));  f = max(f, fwd(z, dim));
  555.       }
  556.       back(x, dim) = b;  fwd(x, dim) = f;
  557.     }
  558.       }
  559.       break;
  560.  
  561.  
  562.     case ACAT:
  563.  
  564.       if( dim == COL )
  565.       { BOOLEAN bad_gap;
  566.     LENGTH actual_size,
  567.     adjust_indent, frame_size, back_edge, adjust_inc, inc;
  568.     int adjustable_gaps;
  569.       
  570.  
  571.     /*********************************************************************/
  572.     /*                                                                   */
  573.     /*  The first step is to calculate the following values:             */
  574.     /*                                                                   */
  575.     /*    bad_gap          TRUE if an adjust-preventing gap is found     */
  576.     /*                                                                   */
  577.     /*    actual_size      the actual size of x;                         */
  578.     /*                                                                   */
  579.     /*    adjustable_gaps  the number of gaps to the right of the        */
  580.     /*                     right-most tab gap.                           */
  581.     /*                                                                   */
  582.     /*  These make it easy to perform adjustment on a second pass, if    */
  583.     /*  required.                                                        */
  584.     /*                                                                   */
  585.     /*********************************************************************/
  586.  
  587.     FirstDefinite(x, link, y);
  588.     if( link == x )  break;  /* no definite children, nothing to print */
  589.     bad_gap = FALSE;
  590.     adjustable_gaps = 0;
  591.     back_edge = xmk - xb;
  592.     mk = back_edge + back(y, dim);
  593.     frame_size = xb + xf;
  594.     prev = y;
  595.     NextDefiniteWithGap(x, link, y, g);
  596.     while( link != x )
  597.     {
  598.       save_actual_gap(g) = ActualGap(fwd(prev, dim), back(y, dim),
  599.         fwd(y, dim), &gap(g), frame_size, mk - back_edge);
  600.       mk += save_actual_gap(g);
  601.       if( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
  602.                        || units(gap(g)) == FRAME_UNIT )
  603.       { bad_gap = TRUE;
  604.       }
  605.       else if( width(gap(g)) > 0 )  adjustable_gaps += 1;
  606.       prev = y;
  607.       NextDefiniteWithGap(x, link, y, g);
  608.     }
  609.     actual_size = mk + fwd(prev, dim) - back_edge;
  610.  
  611.     /*********************************************************************/
  612.     /*                                                                   */
  613.     /*  The second step is to work out whether adjusting is required     */
  614.     /*  or not, and if so by how much, using the following variables:    */
  615.     /*                                                                   */
  616.     /*    adjust_inc       The amount of adjustment to apply initially.  */
  617.     /*                                                                   */
  618.     /*    adjust_indent    initial indent for centring etc.              */
  619.     /*                                                                   */
  620.     /*  NB adjust_inc may be negative, if the optimal paragraph          */
  621.     /*  breaker has chosen to shrink some gaps.                          */
  622.     /*                                                                   */
  623.     /*********************************************************************/
  624.  
  625.     adjust_indent = 0;
  626.     switch( display_style(save_style(x)) )
  627.     {
  628.       case DO_ADJUST:    padj = ALL_ADJUST;
  629.                 break;
  630.     
  631.       case DISPLAY_CENTRE:    if( actual_size <= frame_size )
  632.                 { adjust_indent = (frame_size - actual_size)/2;
  633.                   padj = LAST_ADJUST;
  634.                 }
  635.                 else padj = ALL_ADJUST;
  636.                 debug1(DGP, DD, "cdisp %s", EchoObject(x));
  637.                 break;
  638.  
  639.       case DISPLAY_RIGHT:    if( actual_size <= frame_size )
  640.                 { adjust_indent = frame_size - actual_size;
  641.                   padj = LAST_ADJUST;
  642.                 }
  643.                 else padj = ALL_ADJUST;
  644.                 debug1(DGP, DD, "rdisp %s", EchoObject(x));
  645.                 break;
  646.     }
  647.  
  648.     if( padj == ALL_ADJUST && adjustable_gaps > 0 && !bad_gap )
  649.     { adjust_inc = (frame_size - actual_size) / adjustable_gaps;
  650.       inc = max(adjust_inc, 0);
  651.     }
  652.     else adjust_inc = inc = 0;
  653.  
  654.     debug2(DGP, DD, "ACAT %s %s",
  655.       EchoStyle(&save_style(x)), EchoObject(x));
  656.     debug3(DGP,DD,"frame_size = %s, actual_size = %s, adjustable_gaps = %d",
  657.       EchoLength(frame_size), EchoLength(actual_size), adjustable_gaps);
  658.     debug2(DGP,DD,"bad_gap = %s, adjust_inc = %s",
  659.       bool(bad_gap), EchoLength(adjust_inc));
  660.  
  661.     /*********************************************************************/
  662.     /*                                                                   */
  663.     /*  The third and final step is to traverse x, fixing subobjects.    */
  664.     /*                                                                   */
  665.     /*********************************************************************/
  666.  
  667.     FirstDefinite(x, link, y);
  668.     prev = y;
  669.     mk = xmk - back(x, dim) + back(y, dim) + adjust_indent;
  670.     NextDefiniteWithGap(x, link, y, g);
  671.     while( link != x )
  672.     {
  673.       /* fix previous definite now we know it is not the last one  */
  674.       if( width(gap(g)) > 0 )
  675.       { FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim) + inc,
  676.           dim, adjust, NO_SUPPRESS, LAST_ADJUST, pg, count);
  677.         mk += save_actual_gap(g) + adjust_inc;
  678.       }
  679.       else
  680.       { FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
  681.           dim, adjust, NO_SUPPRESS, LAST_ADJUST, pg, count);
  682.         mk += save_actual_gap(g);
  683.       }
  684.  
  685.       /* move on to next subobject */
  686.       prev = y;
  687.       NextDefiniteWithGap(x, link, y, g);
  688.     }
  689.  
  690.     /* fix the last definite subobject, prev, which must exist */
  691.     FixAndPrintObject(prev, mk, back(prev, dim),
  692.       frame_size - (mk - xmk) - back(x, dim),
  693.       dim, adjust, NO_SUPPRESS, LAST_ADJUST, pg, count);
  694.       }
  695.       else for( link = Down(x);  link != x;  link = NextDown(link) )
  696.       {    Child(y, link);
  697.     if( !is_definite(type(y)) )  continue;
  698.     FixAndPrintObject(y, xmk, xb, xf, dim, adjust, NO_SUPPRESS,
  699.         padj,pg,count);
  700.       }
  701.       back(x, dim) = xb;  fwd(x, dim) = xf;
  702.       break;
  703.  
  704.  
  705.     case COL_THR:
  706.     case ROW_THR:
  707.  
  708.       /* find and delete the child number count of y */
  709.       assert( (type(x) == COL_THR) == (dim == COL), "FixAndPrintObject: thr!" );
  710.       for( link = Down(x), uplink = Up(x), i = 1;
  711.     link != x && uplink != x && i < count;
  712.     link = NextDown(link), uplink = NextUp(uplink), i++ );
  713.       assert( link != x && uplink != x, "FixAndPrintObject: link or uplink!" );
  714.       CountChild(y, link, count);
  715.       MoveLink(uplink, link, CHILD);  DeleteLink(link);  /* IMPORTANT!!! */
  716.       assert( type(y) != GAP_OBJ, "FAPO: THR!");
  717.  
  718.       /* assign size if not done previously */
  719.       if( thr_state(x) != FINALSIZE )
  720.       {    back(x, dim) = xb;  fwd(x, dim) = xf;
  721.     thr_state(x) = FINALSIZE;
  722.       }
  723.  
  724.       /* *** else been here before, size is already decided; do nothing
  725.       {    if( back(x, dim) > xb || fwd(x, dim) > xf )
  726.     { Error(WARN, &fpos(y), "wrong %s chosen (sorry!)",
  727.         dim == COL ? "column width" : "row height");
  728.       if( back(x, dim) > xb )  back(x, dim) = xb;
  729.       if( fwd(x, dim)  > xf )  fwd(x, dim)  = xf;
  730.     }
  731.       }
  732.       *** */
  733.  
  734.       /* fix y */
  735.       FixAndPrintObject(y, xmk, back(x, dim), fwd(x, dim), dim, LAST_ADJUST,
  736.     NO_SUPPRESS, padj, pg, count);
  737.       if( Up(x) == x )  Dispose(x);
  738.       break;
  739.  
  740.  
  741.     default:
  742.     
  743.       Error(INTERN, no_fpos, "FixAndPrint: found %s", Image(type(x)));
  744.       break;
  745.  
  746.   } /* end switch */
  747.   debug2(DGP, D, "] FixAndPrintObject returning (size now %s,%s).",
  748.     EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
  749. } /* end FixAndPrintObject */
  750.