aboutsummaryrefslogblamecommitdiffstats
path: root/z23.c
blob: cc2955a3100948ccfdf84422a75355117c5bae98 (plain) (tree)
1
2
3
4

                                                                               
                                                                               
                                                                               





























































































































                                                                                
                                                                          


                                                                    
                                                                



































                                                       












                                                                               











                                                                    















                                                                               












                                                                        
                                                   
















                                                                             
                                                             


                                                           
                                                                    























































































                                                                                
                                
       













                                                                            








                                                     















                                                                              
                                                                



                                                                         







                                           
                                
       





















                                                                            
































                                                                       
                                 
       


















                                                                              
       

                                                                    






                                           
                                       
       






                                                                   
                                                                      






                                       
           







                                                                      
                                            



                                                                    






                                           
                                  
       






                                                                          
 












                                                                        
           














                                                                             







                                           
                                     
       









                                                                      

             


                                                                  

















                                                                  



                                                                              






























                                                                                 











































































































































































































































                                                                                    
                                                          
























































































                                                                                                      
                                                                            









                                                                             
                                                                           














































































































































                                                                                 

                                                                 










































                                                                                 










                                                                        




                                                           
 



                                                                    
/*@z23.c:Galley Printer:ScaleFactor()@****************************************/
/*                                                                           */
/*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.22)                       */
/*  COPYRIGHT (C) 1991, 2000 Jeffrey H. Kingston                             */
/*                                                                           */
/*  Jeffrey H. Kingston (jeff@cs.usyd.edu.au)                                */
/*  Basser Department of Computer Science                                    */
/*  The University of Sydney 2006                                            */
/*  AUSTRALIA                                                                */
/*                                                                           */
/*  This program is free software; you can redistribute it and/or modify     */
/*  it under the terms of the GNU General Public License as published by     */
/*  the Free Software Foundation; either Version 2, or (at your option)      */
/*  any later version.                                                       */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA   */
/*                                                                           */
/*  FILE:         z23.c                                                      */
/*  MODULE:       Galley Printer                                             */
/*  EXTERNS:      FixAndPrintObject()                                        */
/*                                                                           */
/*****************************************************************************/
#include "externs.h"
#define	NO_SUPPRESS	FALSE
#define	SUPPRESS	TRUE
#define word_equal(x, str)  (is_word(type(x)) && StringEqual(string(x), str))


/*****************************************************************************/
/*                                                                           */
/*  static float ScaleFactor(avail_size, inner_size)                         */
/*                                                                           */
/*  Return the scale factor for this scaling, or 0 if impossible.            */
/*                                                                           */
/*****************************************************************************/

static float ScaleFactor(FULL_LENGTH avail_size, FULL_LENGTH inner_size)
{ float scale_factor;
  scale_factor = avail_size <= 0 ? 0 :
		 inner_size <= 0 ? 0 : (float) avail_size / inner_size;
  return scale_factor;
}


/*@::FindAdjustIncrement()@***************************************************/
/*                                                                           */
/*  static FULL_LENGTH FindAdjustIncrement(x, frame_size, dim)               */
/*                                                                           */
/*  Find the amount by which to increase the width of the subobjects of      */
/*  concatenation object x so that it is adjusted to fill size frame_size.   */
/*                                                                           */
/*****************************************************************************/

static FULL_LENGTH FindAdjustIncrement(OBJECT x, FULL_LENGTH frame_size,int dim)
{ OBJECT y, link, prev, g;
  int adjustable_gaps;  BOOLEAN jn;
  FULL_LENGTH inc, mk, actual_size;

  debug2(DGP, DD, "FindAdjustIncrement(x, %s, %s)",
	EchoLength(frame_size), dimen(dim));
  FirstDefinite(x, link, prev, jn);
  if( link != x )
  { adjustable_gaps = 0;
    mk = back(prev, dim);
    NextDefiniteWithGap(x, link, y, g, jn);
    while( link != x )
    { if ( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
				    || units(gap(g)) == FRAME_UNIT )
      {	debug0(DGP, DD, "FindAdjustIncrement returning 0 (tab gap)");
	return 0;
      }
      mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
		frame_size, mk);
      prev = y;
      adjustable_gaps++;
      NextDefiniteWithGap(x, link, y, g, jn);
    }
    actual_size = mk + fwd(prev, dim);
    debug2(DGP, DD, "  actual_size = %s, adjustable_gaps = %d",
	EchoLength(actual_size), adjustable_gaps);
    inc = adjustable_gaps==0 ? 0 : (frame_size - actual_size) / adjustable_gaps;
  }
  else inc = 0;
  debug1(DGP, DD, "FindAdjustIncrement returning %s", EchoLength(inc));
  return inc;
} /* end FindAdjustIncrement */


/*@::FixAndPrintObject()@*****************************************************/
/*                                                                           */
/*  FixAndPrintObject(x, xmk, xb, xf, dim, suppress, pg, count)              */
/*                                                                           */
/*  Fix the absolute position of object x in dimension dim, in such a way    */
/*  that the principal mark of x has coordinate xmk, and x has actual size   */
/*  (xb, xf), where xb >= back(x, dim) and xf >= fwd(x, dim).                */
/*                                                                           */
/*  Actually, in the case where x includes an object lying on a thread       */
/*  leading outside x, the final size of x may be different.  Because        */
/*  of this, the procedure sets back(x, dim) and fwd(x, dim) to the actual   */
/*  size of x upon return.  The caller assumes that x will exactly occupy    */
/*  this space back(x, dim), fwd(x, dim).                                    */
/*                                                                           */
/*  The suppress parameter is true if a temporary suppression of adjustment  */
/*  in this direction is in effect (because a neighbouring adjustment has    */
/*  already been done).  This is for @HAdjust and @VAdjust, not @PAdjust.    */
/*                                                                           */
/*  If dim == COLM, the coordinate information is merely stored; but if      */
/*  dim == ROWM, it is used to generate PostScript for printing x.           */
/*                                                                           */
/*  Parameter pg records the height of the current page.  This is used       */
/*  to correct for the fact that Lout places its origin at the top left,     */
/*  while PostScript places its origin at the bottom left.  This correction  */
/*  cannot be made by transforming user space.                               */
/*                                                                           */
/*  x is child number count of its parent (used by COL_THR and ROW_THR only) */
/*                                                                           */
/*****************************************************************************/

void FixAndPrintObject(OBJECT x, FULL_LENGTH xmk, FULL_LENGTH xb,
  FULL_LENGTH xf, int dim, BOOLEAN suppress, FULL_LENGTH pg, int count)
{ OBJECT y, link, prev, g, uplink, z, face, thr;
  FULL_LENGTH mk, ymk, frame_size, back_edge, yb, yf, inc, f;
  int i; float scale_factor;  BOOLEAN jn;
  debug8(DGP, DD, "[ FixAndPrintObject(%s %s, %s, %s,%s, %s, %s, pg, %d)",
    Image(type(x)),
    ((type(x) == WORD || type(x) == QWORD) ? string(x) : STR_EMPTY),
    EchoLength(xmk), EchoLength(xb), EchoLength(xf),dimen(dim),
    (suppress == SUPPRESS ? "suppress" : "no_suppress"), count);
  debug2(DGP, DD, "  size(x) = %s,%s;  x =",
    EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
  ifdebug(DGP, DD, DebugObject(x));

  /*** start and stop debugging
  if( dim == COLM && is_word(type(x)) &&
      StringEqual(string(x), AsciiToFull("STARTBUG")) )
    dbg[DGP].on[DD] = dbg[DGP].on[D] = TRUE;
  if( dim == COLM && is_word(type(x)) &&
      StringEqual(string(x), AsciiToFull("STOPBUG")) )
    dbg[DGP].on[DD] = dbg[DGP].on[D] = FALSE;
  *** */


  switch( type(x) )
  {

    case CLOSURE:
    case NULL_CLOS:
    case PAGE_LABEL:
    case CROSS:
    case FORCE_CROSS:
    
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case START_HVSPAN:
    case START_HSPAN:
    case START_VSPAN:

      CountChild(y, DownDim(x, dim), count);
      if( type(y) == HSPANNER || type(y) == VSPANNER )
      {
        Child(z, Down(y));
	Parent(thr, UpDim(x, dim));
	save_mark(y) = xmk - back(thr, dim) + back(z, dim);

        /* do the fix now if the first column is also the last one */
	if( ++spanner_fixed(y) == spanner_count(y) )
	{
	  debug6(DGP, DD, "  f+last SPAN: yf = max(%s + %s - %s, %s, %s - %s)",
	    EchoLength(xmk), EchoLength(xf), EchoLength(save_mark(y)),
	    EchoLength(fwd(z, dim)),
	    EchoLength(bfc(constraint(y))), EchoLength(back(z, dim)));
	  yf = find_max(xmk + xf - save_mark(y), fwd(z, dim));
	  yf = find_max(yf, bfc(constraint(y)) - back(z, dim));
          FixAndPrintObject(z, save_mark(y), back(z, dim), yf, dim,FALSE,pg,1);
	}
      }
      else
      {
        FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
	back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      }
      break;


    case HSPAN:
    case VSPAN:

      /* do the fix on the last one */
      CountChild(y, DownDim(x, dim), count);
      if( type(y) == HSPANNER || type(y) == VSPANNER )
      {
	if( ++spanner_fixed(y) == spanner_count(y) )
	{
          Child(z, Down(y));
	  debug6(DGP, DD, "  last SPAN: yf = max(%s + %s - %s, %s, %s - %s)",
	    EchoLength(xmk), EchoLength(xf), EchoLength(save_mark(y)),
	    EchoLength(fwd(z, dim)),
	    EchoLength(bfc(constraint(y))), EchoLength(back(z, dim)));
	  yf = find_max(xmk + xf - save_mark(y), fwd(z, dim));
	  yf = find_max(yf, bfc(constraint(y)) - back(z, dim));
          FixAndPrintObject(z, save_mark(y), back(z, dim), yf, dim,FALSE,pg,1);
	}
      }
      break;


    case WORD:
    case QWORD:
    
      if( dim == COLM )
      {
	/* save horizontal position for PrintWord below */
	word_save_mark(x) = xmk;

	/* if first occurrence of this font on this page, notify font */
	if( string(x)[0] != '\0' )
	{ face = finfo[word_font(x)].original_face;
	  if( font_page(face) < font_curr_page )
	  { debug3(DFT, DD, "FAPO: x = %s, word_font = %d, face = %s",
	      string(x), word_font(x), EchoObject(face));
	    FontPageUsed(face);
	  }
	}
      }
      else
      {
	debug4(DGP, D, /* underline(x) == UNDER_UNDEF, */
	  "  FAPO %s %s %s (underline = %s)", EchoFilePos(&fpos(x)),
	  Image(type(x)),
	  string(x), underline(x) == UNDER_OFF ? "UNDER_OFF" :
		     underline(x) == UNDER_ON  ? "UNDER_ON" : "UNDER_UNDEF");
	assert( underline(x) == UNDER_OFF || underline(x) == UNDER_ON,
	  "FixAndPrintObject: underline(x)!" );
	if( string(x)[0] != '\0' )
	{ BackEnd->PrintWord(x, word_save_mark(x), pg - xmk);
	  if( underline(x) == UNDER_ON )
	  {
	    FontWordSize(x);  /* to restore fwd(x, COLM) */
	    BackEnd->PrintUnderline(word_font(x), word_save_mark(x),
	      word_save_mark(x) + fwd(x, COLM), pg - xmk);
	  }
	}
      }
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case WIDE:
    case HIGH:
    
      CountChild(y, Down(x), count);
      if( (dim == COLM) == (type(x) == WIDE) )
      { yf = bfc(constraint(x)) - back(y, dim);
        FixAndPrintObject(y, xmk, back(y,dim), yf, dim, NO_SUPPRESS, pg,count);
        back(x, dim) = xb;  fwd(x, dim) = xf;
      }
      else
      {	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
	back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      }
      break;


    case HSHIFT:
    case VSHIFT:

      CountChild(y, Down(x), count);
      if( (dim == COLM) == (type(x) == HSHIFT) )
      {
	/* work out the size of the shift depending on the units */
	f = FindShift(x, y, dim);
	ymk = xmk - f;
	yb = find_max(0, xb - f);
	yf = find_max(0, xf + f);
	FixAndPrintObject(y, ymk, yb, yf, dim, suppress, pg, count);

	/* recalculate the size of x as in MinSize */
	f = FindShift(x, y, dim);
	back(x, dim) = find_min(MAX_FULL_LENGTH, find_max(0, back(y, dim) + f));
	fwd(x, dim)  = find_min(MAX_FULL_LENGTH, find_max(0, fwd(y, dim)  - f));
      }
      else
      {	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
	back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      }
      break;


    case HCONTRACT:
    case VCONTRACT:
    
      CountChild(y, Down(x), count);
      if( (dim == COLM) == (type(x) == HCONTRACT) )
      {	FixAndPrintObject(y, xmk, back(y,dim), fwd(y,dim), dim,
	  NO_SUPPRESS, pg, count);
        back(x, dim) = xb;  fwd(x, dim) = xf;
      }
      else
      {	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
        back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      }
      break;


    case ONE_COL:
    case ONE_ROW:
    case HLIMITED:
    case VLIMITED:
    case HEXPAND:
    case VEXPAND:
    
      CountChild(y, Down(x), count);
      if( (dim == COLM) == (type(x) == ONE_COL || type(x) == HEXPAND) )
      { FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count);
        back(x, dim) = xb;  fwd(x, dim) = xf;
      }
      else
      {	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
	back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      }
      break;


    case VSCALE:

      debug0(DRS, DD, "FixAndPrintObject at VSCALE");
      CountChild(y, Down(x), count);
      if( BackEnd->scale_avail )
      {
	if( dim == COLM )
	  FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count);
	else if( (scale_factor = ScaleFactor(xb+xf, size(y, ROWM))) > 0 )
	{ BackEnd->SaveGraphicState(y);
	  BackEnd->CoordTranslate(0,
	    pg - (xmk - xb + (FULL_LENGTH) (back(y, ROWM) * scale_factor)));
	  BackEnd->CoordScale(1.0, scale_factor);
	  FixAndPrintObject(y, 0, back(y,ROWM), fwd(y,ROWM), dim,
	    NO_SUPPRESS, 0, count);
	  BackEnd->RestoreGraphicState();
	}
	else if( !is_word(type(y)) || string(y)[0] != '\0' )
	  Error(23, 1, "object deleted (it cannot be scaled vertically)",
	    WARN, &fpos(x));
      }
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case HSCALE:
    
      debug0(DRS, DD, "FixAndPrintObject at HSCALE");
      CountChild(y, Down(x), count);
      if( BackEnd->scale_avail )
      {	if( dim == COLM )
        { save_mark(x) = xmk;
	  bc(constraint(x)) = xb;
	  fc(constraint(x)) = xf;
          if( (scale_factor = ScaleFactor(xb+xf, size(y, COLM))) > 0 )
	    FixAndPrintObject(y, 0, back(y, COLM), fwd(y, COLM), dim,
	      NO_SUPPRESS, pg, count);
          else if( !is_word(type(y)) || string(y)[0] != '\0' )
	    Error(23, 2, "object deleted (it cannot be scaled horizontally)",
	      WARN, &fpos(y));
        }
        else if( (scale_factor =
	  ScaleFactor(bc(constraint(x))+fc(constraint(x)),size(y,COLM))) > 0 )
        { BackEnd->SaveGraphicState(y);
	  BackEnd->CoordTranslate(save_mark(x) - bc(constraint(x))
	       + (FULL_LENGTH) (back(y, COLM)*scale_factor), 0);
	  BackEnd->CoordScale(scale_factor, 1.0);
          FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count);
	  BackEnd->RestoreGraphicState();
        }
      }
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case SCALE:

      CountChild(y, Down(x), count);
      if( BackEnd->scale_avail )
      {
        if( dim == COLM )
        { assert( bc(constraint(x)) > 0, "FAPO: horizontal scale factor!" );
	  save_mark(x) = xmk;
	  yb = xb * SF / bc(constraint(x));
	  yf = xf * SF / bc(constraint(x));
          FixAndPrintObject(y, 0, yb, yf, dim, NO_SUPPRESS, pg, count);
        }
        else
        { assert( fc(constraint(x)) > 0, "FAPO: vertical scale factor!" );
	  yb = xb * SF / fc(constraint(x));
	  yf = xf * SF / fc(constraint(x));
	  BackEnd->SaveGraphicState(y);
	  BackEnd->CoordTranslate(save_mark(x), pg - xmk);
	  BackEnd->CoordScale( (float)bc(constraint(x))/SF,
	    (float)fc(constraint(x))/SF);
          FixAndPrintObject(y, 0, yb, yf, dim, NO_SUPPRESS, 0, count);
	  BackEnd->RestoreGraphicState();
        }
      }
      else if( bc(constraint(x)) == SF && fc(constraint(x)) == SF )
      {
	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      }
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case KERN_SHRINK:

      CountChild(y, LastDown(x), count);
      if( dim == COLM )
      { FixAndPrintObject(y, xmk, back(y,dim), fwd(y,dim), dim,
	  NO_SUPPRESS, pg, count);
      }
      else
      {	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
        back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      }
      break;


    case BACKGROUND:
 
      /* this object has the size of its second child; but its first */
      /* child gets printed too, in the same space                   */
      CountChild(y, Down(x), count);
      FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      CountChild(y, LastDown(x), count);
      FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      break;


    case ROTATE:
    
      CountChild(y, Down(x), count);
      if( BackEnd->rotate_avail )
      {
        if( dim == COLM )
        { CONSTRAINT colc, rowc, yc;
          save_mark(x) = xmk;
	  SetConstraint(colc, back(x,COLM), MAX_FULL_LENGTH, fwd(x,COLM));
	  SetConstraint(rowc, back(x,ROWM), MAX_FULL_LENGTH, fwd(x,ROWM));
	  RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc,COLM);
	  FixAndPrintObject(y, 0, bc(yc), fc(yc), COLM,NO_SUPPRESS,pg,count);
        }
        else
        { CONSTRAINT colc, rowc, yc;
	  BackEnd->SaveGraphicState(y);
	  BackEnd->CoordTranslate(save_mark(x), pg - xmk);
	  BackEnd->CoordRotate(sparec(constraint(x)));
	  SetConstraint(colc, back(x,COLM), MAX_FULL_LENGTH, fwd(x,COLM));
	  SetConstraint(rowc, back(x,ROWM), MAX_FULL_LENGTH, fwd(x,ROWM));
	  RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc, ROWM);
	  FixAndPrintObject(y, 0, bc(yc), fc(yc), ROWM, NO_SUPPRESS,0,count);
	  BackEnd->RestoreGraphicState();
        }
      }
      else if( sparec(constraint(x)) == 0 )
	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case PLAIN_GRAPHIC:

      CountChild(y, LastDown(x), count);
      if( BackEnd->plaingraphic_avail )
      {
	if( dim == COLM )
	{
	  back(x, dim) = xb;
	  fwd(x, dim)  = xf;
	  save_mark(x) = xmk - back(x, dim);
	  debug2(DGP, DD, "PLAIN_GRAPHIC COLM storing size %s, %s",
	    EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
          FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
	}
	else
	{ OBJECT tmp, pre, post;
          Child(tmp, Down(x));
          if( type(tmp) == VCAT )
          { Child(pre, Down(tmp));
            Child(post, LastDown(tmp));
          }
          else pre = tmp, post = nilobj;
	  back(x, dim) = xb;
	  fwd(x, dim)  = xf;
          BackEnd->PrintPlainGraphic(pre, save_mark(x),
	    pg - (xmk - back(x, dim)), x);
          FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
          if( post != nilobj )
	    BackEnd->PrintPlainGraphic(post, save_mark(x),
	      pg - (xmk - back(x, dim)), x);
	}
      }
      else
	FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case GRAPHIC:
    
      CountChild(y, LastDown(x), count);
      if( BackEnd->graphic_avail )
      {
	if( dim == COLM )
	{
	  /* if first occurrence of this font on this page, notify font */
	  if( font(save_style(x)) > 0 )
	  { face = finfo[font(save_style(x))].original_face;
	    if( font_page(face) < font_curr_page )  FontPageUsed(face);
	  }

	  back(x, dim) = xb;
	  fwd(x, dim)  = xf;
	  debug2(DGP, DD, "GRAPHIC COLM storing size %s, %s",
	    EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
	  save_mark(x) = xmk - back(x, COLM);
          FixAndPrintObject(y, xb, xb, xf, dim, NO_SUPPRESS, pg, count);
	}
	else
	{ OBJECT tmp, pre, post;
          Child(tmp, Down(x));
          if( type(tmp) == VCAT )
          { Child(pre, Down(tmp));
            Child(post, LastDown(tmp));
          }
          else pre = tmp, post = nilobj;
	  back(x, dim) = xb;
	  fwd(x, dim)  = xf;

	  BackEnd->SaveTranslateDefineSave(x, save_mark(x),
	    pg - (xmk + fwd(x, ROWM)));
          BackEnd->PrintGraphicObject(pre);
          BackEnd->RestoreGraphicState();
          FixAndPrintObject(y, xb, xb, xf, dim, NO_SUPPRESS, xb + xf, count);
          if( post != nilobj )  BackEnd->PrintGraphicObject(post);
          BackEnd->RestoreGraphicState();
	}
      }
      else
        FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case INCGRAPHIC:
    case SINCGRAPHIC:

      CountChild(y, Down(x), count);
      if( BackEnd->incgraphic_avail )
      {
	if( dim == COLM )
	{ save_mark(x) = xmk;
	  if( incgraphic_ok(x) )
	  { debug2(DGP, DD, "  %s (style %s)",
	      EchoObject(x), EchoStyle(&save_style(x)));
	    face = finfo[font(save_style(x))].original_face;
	    if( font_page(face) < font_curr_page )
	    { debug3(DFT, DD, "FAPO-IG: x = %s, font = %d, face = %s",
		string(x), font(save_style(x)), EchoObject(face));
	      FontPageUsed(face);
	    }
	  }
	}
	else if( incgraphic_ok(x) )
	  BackEnd->PrintGraphicInclude(x, save_mark(x), pg - xmk);
      }
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case SPLIT:
    
      link = DownDim(x, dim);  CountChild(y, link, count);
      FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count);
      back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
      break;


    case VCAT:
    case HCAT:

      if( (type(x) == VCAT) == (dim == ROWM) )
      { 
	debug6(DGP, DD, "[ FAPO-CAT %s (%s,%s): xmk %s, xb %s, xf %s",
	    Image(type(x)), EchoLength(back(x, dim)), EchoLength(fwd(x, dim)),
	    EchoLength(xmk), EchoLength(xb), EchoLength(xf));

	FirstDefinite(x, link, prev, jn);
	if( link != x )
	{

	  /* handle the special case of a 0rt gap at the beginning (left  */
	  /* justify) by converting it to 0ie but increasing fwd(prev)    */
	  /* to the max. possible                                         */
	  NextDefiniteWithGap(x, link, y, g, jn);
	  if( link != x && mode(gap(g)) == TAB_MODE &&
	      units(gap(g)) == AVAIL_UNIT && width(gap(g)) == 0 )
	  {
	    debug2(DGP, DD, "  FAPO-CAT converting 0rt (back(x, dim) %s, xb %s)",
	      EchoLength(back(x, dim)), EchoLength(xb));
	    fwd(prev, dim) += xb - back(x, dim);
	    back(x, dim) = xb;
	    mode(gap(g)) = EDGE_MODE;
	    units(gap(g)) = FIXED_UNIT;
	  }
	  FirstDefinite(x, link, prev, jn);

	  /* the frame size is the total width actually available */
	  frame_size = back(x, dim) + xf;

	  /* back_edge is where the first element begins */
	  back_edge = xmk - back(x, dim);

	  /* inc is the adjust increment, used when adjusting gaps */
	  if( adjust_cat(x) && !suppress )
	    inc = FindAdjustIncrement(x, frame_size, dim);
	  else inc = 0;

	  mk = back_edge + back(prev, dim);
	  debug4(DGP, DD, "  FAPO-CAT back_edge %s, mk %s, framesize %s, inc %s",
	    EchoLength(back_edge), EchoLength(mk), EchoLength(frame_size),
	    EchoLength(inc));

	  NextDefiniteWithGap(x, link, y, g, jn);

	  while( link != x )
	  {
	    if( mode(gap(g)) == TAB_MODE && units(gap(g)) == AVAIL_UNIT &&
		width(gap(g))==FR )
	    {
	      /* object is followed by 1rt gap, give it full space to print */
	      debug5(DGP,D,"  FAPO (a) calling FAPO(%s, %s, %s, max(%s, %s))",
	        Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
		EchoLength(fwd(prev, dim)), EchoLength(xmk+xf-mk-size(y,dim)));
	      FixAndPrintObject(prev, mk, back(prev, dim),
		find_max(fwd(prev, dim), xmk+xf-mk - size(y, dim)),
		dim, NO_SUPPRESS, pg, count);
	    }
	    else
	    {
	      debug5(DGP, DD, "  FAPO-CAT (b) calling FAPO(%s, %s, %s, %s+%s)",
	        Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
		EchoLength(fwd(prev, dim)), EchoLength(inc));
	      FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim) + inc,
	        dim, NO_SUPPRESS, pg, count);
	    }
	    /* NB fwd(prev, dim) may be changed by the call to FAPO */
	    mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
		    frame_size, mk - back_edge);
	    prev = y;
	    NextDefiniteWithGap(x, link, y, g, jn);
	  }
	  if( suppress )
	  {
	    debug4(DGP, DD, "  FAPO-CAT (c) calling FAPO(%s, %s, %s, %s)",
	      Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
	      EchoLength(fwd(prev, dim)));
	    FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
	      dim, NO_SUPPRESS, pg, count);
	  }
	  else
	  {
	    debug5(DGP, DD,"  FAPO-CAT (d) calling FAPO(%s, %s, %s, max(%s, %s))",
	      Image(type(prev)), EchoLength(mk), EchoLength(back(prev, dim)),
	      EchoLength(fwd(prev, dim)), EchoLength(xmk + xf - mk));
	    FixAndPrintObject(prev, mk, back(prev,dim),
	      find_max(fwd(prev, dim), xmk + xf - mk),
	      dim, NO_SUPPRESS, pg, count);
	  }
	  back(x, dim) = find_max(back(x, dim), xb);
	  fwd(x, dim) = mk + fwd(prev, dim) - back_edge - back(x, dim);
	}
	else back(x, dim) = xb, fwd(x, dim) = xf;
	debug0(DGP, DD, "] FAPO-CAT returning.");
      }
      else
      { OBJECT start_group, zlink, m;  BOOLEAN dble_found;
	FULL_LENGTH b, f, dlen;
	start_group = nilobj;  dble_found = FALSE;  dlen = 0;
	debug0(DGP, DD, "  groups beginning.");
	FirstDefinite(x, link, y, jn);
	if( link != x )
	{
	  /* start first group, with or without join */
	  b = back(y, dim);
	  f = fwd(y, dim);
	  m = y;
	  start_group = link;
	  dble_found = !jn;
	  debug4(DGP, DD, "  starting first group %s (%sdbl_found): b = %s, f = %s",
	    Image(type(y)), dble_found ? "" : "not ",
	    EchoLength(b), EchoLength(f));
	
	  NextDefiniteWithGap(x, link, y, g, jn);
	  while( link != x )
	  {
	    if( !jn )
	    {
	      /* finish off and fix the group ending just before g */
	      debug2(DGP, DD, "  finishing group: b = %s, f = %s",
		EchoLength(b), EchoLength(f));
	      FixAndPrintObject(m, xmk+b, b, xf-b, dim,
		NO_SUPPRESS, pg, count);
	      b = back(m, dim);  f = fwd(m, dim);
	      for( zlink = start_group;  zlink != link;  zlink=NextDown(zlink) )
	      { CountChild(z, zlink, count);
		if( !is_definite(type(z)) || z == m )  continue;
		FixAndPrintObject(z, xmk + b, b, xf - b, dim,
		  SUPPRESS, pg, count);
		b = find_max(b, back(z, dim));  f = find_max(f, fwd(z, dim));
	      }
	      dlen = find_max(dlen, b + f);
	      dble_found = TRUE;
	      start_group = nilobj;

	      /* start new group */
	      b = back(y, dim);
	      f = fwd(y, dim);
	      m = y;
	      start_group = link;
	      debug2(DGP, DD, "  starting group: b = %s, f = %s",
		EchoLength(b), EchoLength(f));
	    }
	    else
	    {
	      /* continue with current group */
	      b = find_max(b, back(y, dim));
	      f = find_max(f, fwd(y, dim));
	      if( fwd(y, dim) > fwd(m, dim) )  m = y;
	      debug2(DGP, DD, "  continuing group: b = %s, f = %s",
		EchoLength(b), EchoLength(f));
	    }

	    NextDefiniteWithGap(x, link, y, g, jn);
	  }
	  assert( start_group != nilobj, "FAPO: final start_group!" );

	  if( dble_found || !jn )
	  {
	    /* finish off and fix this last group */
	    debug2(DGP, DD, "  finishing last group: b = %s, f = %s",
	        EchoLength(b), EchoLength(f));
	    FixAndPrintObject(m, xmk+b, b, xf - b, dim, NO_SUPPRESS, pg,count);
	    b = back(m, dim);  f = fwd(m, dim);
	    for( zlink = start_group;  zlink != x;  zlink = NextDown(zlink) )
	    { CountChild(z, zlink, count);
	      if( !is_definite(type(z)) || z == m )  continue;
	      FixAndPrintObject(z, xmk+b, b, xf - b, dim, SUPPRESS, pg, count);
	      b = find_max(b, back(z, dim));  f = find_max(f, fwd(z, dim));
	    }
	    dlen = find_max(dlen, b + f);
	    back(x, dim) = 0;  fwd(x, dim) = dlen;
	  }
	  else
	  {
	    /* finish off and fix this last and only group */
	    debug2(DGP, DD, "  finishing last and only group: b = %s, f = %s",
	      EchoLength(b), EchoLength(f));
	    FixAndPrintObject(m, xmk, xb, xf, dim, NO_SUPPRESS, pg, count);
	    b = back(m, dim);  f = fwd(m, dim);
	    for( zlink = start_group;  zlink != x;  zlink = NextDown(zlink) )
	    { CountChild(z, zlink, count);
	      if( !is_definite(type(z)) || z == m )  continue;
	      FixAndPrintObject(z, xmk, xb, xf, dim, SUPPRESS, pg, count);
	      b = find_max(b, back(z, dim));  f = find_max(f, fwd(z, dim));
	    }
	    back(x, dim) = b;  fwd(x, dim) = f;
	  }
	}
      }
      break;


    case ACAT:

      if( dim == COLM )
      { BOOLEAN will_adjust, adjusting;
	FULL_LENGTH actual_size,
	adjust_indent, frame_size, back_edge, adjust_inc, inc, adjust_sofar;
	int adjustable_gaps, gaps_sofar;
	BOOLEAN underlining; int underline_xstart; FONT_NUM underline_font;
	OBJECT urec, last_bad_gap;
      

	/*********************************************************************/
	/*                                                                   */
	/*  The first step is to calculate the following values:             */
	/*                                                                   */
	/*    last_bad_gap     The rightmost tab gap, or nilobj if none;     */
	/*                                                                   */
	/*    adjustable_gaps  the number of gaps suitable for adjustment;   */
	/*                     i.e. to the right of the right-most tab gap,  */
	/*                     and of non-zero width;                        */
	/*                                                                   */
	/*    actual_size      the actual size of x without adjustment.      */
	/*                                                                   */
	/*  These are needed when adjusting the line.                        */
	/*                                                                   */
	/*********************************************************************/

	FirstDefinite(x, link, y, jn);
	if( link == x )  break;  /* no definite children, nothing to print */

	/*** nasty bug finder 
	{ OBJECT ff = y;
	debugcond1(DGP, DD, word_equal(ff, "@ReportLayout"),
	  "FAPO(%s, COLM)", EchoObject(x));
	debugcond1(DGP, DD, word_equal(ff, "@ReportLayout"),
	  "  adjust_cat(x) = %s", bool(adjust_cat(x)));
	}
	***/

	last_bad_gap = nilobj;
	adjustable_gaps = 0;
	back_edge = xmk - xb;
	mk = back_edge + back(y, dim);
	frame_size = xb + xf;
	prev = y;
	NextDefiniteWithGap(x, link, y, g, jn);
	while( link != x )
	{
	  save_actual_gap(g) = ActualGap(fwd(prev, dim), back(y, dim),
		fwd(y, dim), &gap(g), frame_size, mk - back_edge);
	  mk += save_actual_gap(g);
	  if( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
				       || units(gap(g)) == FRAME_UNIT )
	  { last_bad_gap = g;
	    adjustable_gaps = 0;
	  }
	  else if( width(gap(g)) > 0 )  adjustable_gaps++;
	  prev = y;
	  NextDefiniteWithGap(x, link, y, g, jn);
	}
	actual_size = mk + fwd(prev, dim) - back_edge;

	/*********************************************************************/
	/*                                                                   */
	/*  It is possible that the line cannot be displayed in any          */
	/*  reasonable way, because the paragraph breaker was forced to      */
	/*  produce an overfull line.  In this case, actual_size will        */
	/*  exceed frame_size and there will be no adjustable gaps.  The     */
	/*  solution is to horizontally scale the line if possible, or       */
	/*  else to not print it at all.                                     */
	/*                                                                   */
	/*********************************************************************/

	if( actual_size > frame_size && adjustable_gaps == 0 )
	{ 
	  /* can't be fixed by adjustment, so scale the line or delete it */
	  CONSTRAINT c;
	  SetConstraint(c, 0, frame_size, frame_size);
	  fwd(x, dim) = actual_size;
	  debug2(DGP, DD, "  oversize, actual_size = %s, frame_size = %s",
	      EchoLength(actual_size), EchoLength(frame_size));
	  if( BackEnd->scale_avail && InsertScale(x, &c) )
	  {
	    /* the problem has just been fixed, by inserting a @Scale above x */
	    OBJECT prnt;
	    Parent(prnt, Up(x));
	    Child(y, Down(x));
	    if( actual_size - frame_size < 1 * PT )
	    {
	      /* the correction is probably due to roundoff error, and */
	      /* anyway is too small to print an error message about   */
	    }
	    else if( Down(x) == LastDown(x) && is_word(type(y)) )
	    {
	      Error(23, 3, "word %s horizontally scaled by factor %.2f (too wide for %s paragraph)",
		WARN, &fpos(y), string(y), (float) bc(constraint(prnt)) / SF,
		EchoLength(frame_size));
	    }
	    else
	    {
	      Error(23, 4, "%s object horizontally scaled by factor %.2f (too wide for %s paragraph)",
		WARN, &fpos(x), EchoLength(size(x, COLM)),
		(float) bc(constraint(prnt)) / SF, EchoLength(frame_size));
	    }
	    FixAndPrintObject(prnt, xmk, back(prnt, dim), fwd(prnt, dim), dim,
	      NO_SUPPRESS, pg, count);
	  }
	  else
	  {
	    /* fix the problem by refraining from printing the line */
	    if( size(x, COLM) <= 0 )
	      Error(23, 5, "oversize object has size 0 or less", INTERN, &fpos(x));
	    Child(y, Down(x));
	    if( Down(x) == LastDown(x) && is_word(type(y)) )
	    { Error(23, 6, "word %s deleted (too wide for %s paragraph)",
		WARN, &fpos(y), string(y), EchoLength(frame_size));
	    }
	    else
	    { Error(23, 7, "%s object deleted (too wide for %s paragraph)",
		WARN, &fpos(x), EchoLength(size(x, COLM)), EchoLength(frame_size));
	    }

	    /* delete and dispose every child of x */
	    while( Down(x) != x )
	      DisposeChild(Down(x));
	    y = MakeWord(WORD, STR_EMPTY, &fpos(x));
	    Link(x, y);
	    back(y, COLM) = fwd(y, COLM) = 0;
	    back(y, ROWM) = fwd(y, ROWM) = 0;
	  }
        }
        else
        {

	  /*********************************************************************/
	  /*                                                                   */
	  /*  The line may be displayed in one of four ways:  centred, right-  */
	  /*  justified, adjusted, or none of the above (i.e. left justified). */
	  /*  An overfull line is always adjusted; otherwise, the line will    */
	  /*  be centred or right justified if the display style asks for it;  */
	  /*  otherwise, the line will be adjusted if adjust_cat(x) == TRUE    */
	  /*  (i.e. there is an enclosing @PAdjust) or if the display style is */
	  /*  DO_ADJUST (meaning that this line is one of a paragraph set in   */
	  /*  the adjust or outdent break style, other than the last line);    */
	  /*  otherwise, the line is left justified.                           */
	  /*                                                                   */
	  /*  The second step is to decide which of these four cases holds     */
	  /*  for this line, and to record the decision in these variables:    */
	  /*                                                                   */
	  /*    will_adjust      TRUE if the adjusted style applies; in this   */
	  /*                     case, variables adjust_inc and inc will be    */
	  /*                     set to the appropriate adjustment value;      */
	  /*                                                                   */
	  /*    adjust_indent    If centring or right justification applies,   */
	  /*                     the indent to produce this, else zero.        */
	  /*                                                                   */
	  /*  NB adjust_inc may be negative, if the optimal paragraph breaker  */
	  /*  has chosen to shrink some gaps.                                  */
	  /*                                                                   */
	  /*********************************************************************/

	  if( actual_size > frame_size )
	  { 
	    assert( adjustable_gaps > 0, "FAPO: adjustable_gaps!" );
	    adjust_cat(x) = TRUE;
	    adjust_indent = 0;
	  }
	  else switch( display_style(save_style(x)) )
	  {
	    case DO_ADJUST:	adjust_cat(x) = TRUE;
				adjust_indent = 0;
				debug1(DSF, D,  "adjust %s", EchoObject(x));
				break;
	
	    case DISPLAY_CENTRE: adjust_cat(x) = FALSE;
				adjust_indent = (frame_size - actual_size)/2;
				debug1(DGP, DD, "cdisp %s", EchoObject(x));
				break;

	    case DISPLAY_RIGHT:	adjust_cat(x) = FALSE;
				adjust_indent = frame_size - actual_size;
				debug1(DGP, DD, "rdisp %s", EchoObject(x));
				debug1(DSF, D,  "rdisp %s", EchoObject(x));
				break;

	    default:		/* leave adjust_cat(x) as is */
				adjust_indent = 0;
				break;
	  }

	  debug2(DGP, DD, "ACAT %s %s",
	    EchoStyle(&save_style(x)), EchoObject(x));
	  debug2(DGP, DD, "frame_size = %s, actual_size = %s",
	    EchoLength(frame_size), EchoLength(actual_size));

	  if( adjust_cat(x) && adjustable_gaps > 0  )
	  { will_adjust = TRUE;
	    adjust_inc = (frame_size - actual_size) / adjustable_gaps;
	    inc = find_max(adjust_inc, 0);
	    gaps_sofar = 0;	/* number of gaps adjusted so far */
	    adjust_sofar = 0;	/* total width of adjustments so far */
	    debug2(DGP, DD, "will_adjust: adjustable_gaps = %d, adjust_inc = %s",
	      adjustable_gaps, EchoLength(adjust_inc));
	  }
	  else will_adjust = FALSE;


	  /*********************************************************************/
	  /*                                                                   */
	  /*  The third and final step is to traverse x, fixing subobjects.    */
	  /*  Variable adjusting is true while adjusting is occurring.         */
	  /*                                                                   */
	  /*********************************************************************/

	  underlining = FALSE;
	  adjusting = will_adjust && last_bad_gap == nilobj;
	  FirstDefinite(x, link, y, jn);
	  prev = y;
	  mk = xmk - back(x, dim) + back(y, dim) + adjust_indent;
	  NextDefiniteWithGap(x, link, y, g, jn);
	  while( link != x )
	  {
	    /* check for underlining */
	    if( underline(prev) == UNDER_ON )
	    {
	      debug3(DGP, DD, "  FAPO/ACAT1 underline() := %s for %s %s",
	        bool(FALSE), Image(type(prev)), EchoObject(prev));
	      underline(prev) = UNDER_OFF;
	      if( !underlining )
	      {
	        /* underlining begins here */
	        underlining = TRUE;
	        debug2(DGP, DD, "underlining begins at %s %s",
		  Image(type(prev)), EchoObject(prev));
	        underline_font = is_word(type(prev)) ? word_font(prev) :
		    font(save_style(x));
	        underline_xstart = mk - back(prev, dim);
	      }
	      if( underline(g) == UNDER_OFF )
	      {
	        /* underlining ends here */
	        debug2(DGP, DD, "underlining ends at %s %s",
		  Image(type(prev)), EchoObject(prev));
	        New(urec, UNDER_REC);
	        back(urec, COLM) = underline_xstart;
	        fwd(urec, COLM) = mk + fwd(prev, dim);
	        back(urec, ROWM) = underline_font;
	        underlining = FALSE;
	        Link(Up(prev), urec);
	      }
	    }

	    /* fix previous definite now we know it is not the last one  */
	    if( adjusting && width(gap(g)) > 0 )
	    { int tmp;

	      FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim) + inc,
	        dim, NO_SUPPRESS, pg, count);

	      gaps_sofar++;
	      tmp = ((frame_size - actual_size) * gaps_sofar) / adjustable_gaps;
	      mk += save_actual_gap(g) + (tmp - adjust_sofar);
	      adjust_sofar = tmp;
	    }
	    else
	    {
	      FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
	        dim, NO_SUPPRESS, pg, count);

	      mk += save_actual_gap(g);
	    }
	    prev = y;

	    /* commence adjustment if required */
	    if( !adjusting && will_adjust && g == last_bad_gap )
	      adjusting = TRUE;

	    NextDefiniteWithGap(x, link, y, g, jn);
	  }

	  /* check for underlining */
	  debugcond3(DGP, D, underline(prev) == UNDER_UNDEF,
	    "  underlining is UNDER_UNDEF in %s: %s %s in para:",
	    EchoFilePos(&fpos(prev)), Image(type(prev)), EchoObject(prev));
	  debugcond1(DGP, D, underline(prev)==UNDER_UNDEF, "%s", EchoObject(x));
	  assert( underline(prev) == UNDER_OFF || underline(prev) == UNDER_ON,
	    "FixAndPrint: underline(prev)!" );
	  if( underline(prev) == UNDER_ON )
	  {
	    debug3(DGP, DD, "  FAPO/ACAT1 underline() := %s for %s %s",
	      bool(FALSE), Image(type(prev)), EchoObject(prev));
	    underline(prev) = UNDER_OFF;
	    if( !underlining )
	    {
	      /* underlining begins here */
	      debug2(DGP, DD, "underlining begins at %s %s",
	        Image(type(prev)), EchoObject(prev));
	      underlining = TRUE;
	      underline_font = is_word(type(prev)) ? word_font(prev) :
		    font(save_style(x));
	      underline_xstart = mk - back(prev, dim);
	    }

	    /* underlining must end here */
	    debug2(DGP, DD, "underlining ends at %s %s",
	      Image(type(prev)), EchoObject(prev));
	    New(urec, UNDER_REC);
	    back(urec, COLM) = underline_xstart;
	    fwd(urec, COLM) = mk + fwd(prev, dim);
	    back(urec, ROWM) = underline_font;
	    underlining = FALSE;
	    Link(Up(prev), urec);
	  }

	  /* fix the last definite subobject, prev, which must exist */
	  FixAndPrintObject(prev, mk, back(prev, dim),
	    frame_size - (mk - xmk) - back(x, dim),
	    dim, NO_SUPPRESS, pg, count);

        }
      }
      else for( link = Down(x);  link != x;  link = NextDown(link) )
      {	Child(y, link);
	if( !is_definite(type(y)) )
	{
	  if( type(y) == UNDER_REC )   /* generate an underline now */
	    BackEnd->PrintUnderline(back(y, ROWM), back(y, COLM),
	      fwd(y, COLM), pg - xmk);
	  continue;
	}
	FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count);
      }
      back(x, dim) = xb;  fwd(x, dim) = xf;
      break;


    case COL_THR:
    case ROW_THR:

      /* find and delete the child number count of y */
      assert( (type(x) == COL_THR) == (dim == COLM), "FixAndPrintObject: thr!" );
      for( link = Down(x), uplink = Up(x), i = 1;
	link != x && uplink != x && i < count;
	link = NextDown(link), uplink = NextUp(uplink), i++ );
      assert( link != x && uplink != x, "FixAndPrintObject: link or uplink!" );
      CountChild(y, link, count);
      debug7(DGP, DD, "  fapo of %s (%s,%s) child %d %s (%s,%s)",
	Image(type(x)),
	EchoLength(back(x, dim)), EchoLength(fwd(x, dim)),
	i, Image(type(y)), EchoLength(back(y, dim)), EchoLength(fwd(y, dim)));
      MoveLink(uplink, link, CHILD);  DeleteLink(link);  /* IMPORTANT!!! */
      assert( type(y) != GAP_OBJ, "FAPO: THR!");

      /* assign size if not done previously */
      /* ***
      if( thr_state(x) != FINALSIZE && type(y) != START_HVSPAN &&
	  type(y) != START_HSPAN && type(y) != START_VSPAN &&
	  type(y) != HSPAN && type(y) != VSPAN )
      *** */
      if( thr_state(x) != FINALSIZE )
      {	back(x, dim) = xb;  fwd(x, dim) = xf;
	thr_state(x) = FINALSIZE;
      }

      /* fix y */
      FixAndPrintObject(y, xmk, back(x, dim), fwd(x, dim), dim,
	NO_SUPPRESS, pg, count);
      if( Up(x) == x )  Dispose(x);
      break;


    case BEGIN_HEADER:
    case END_HEADER:
    case SET_HEADER:
    case CLEAR_HEADER:

      if( dim == COLM )
        Error(23, 8, "%s symbol ignored (out of place)", WARN, &fpos(x),
	  Image(type(x)));
      break;


    default:
    
      assert1(FALSE, "FixAndPrintObject:", Image(type(x)));
      break;


  } /* end switch */
  debug2(DGP, DD, "] FixAndPrintObject returning (size now %s,%s).",
	EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
} /* end FixAndPrintObject */