diff options
Diffstat (limited to 'z23.c')
-rw-r--r-- | z23.c | 1237 |
1 files changed, 1237 insertions, 0 deletions
@@ -0,0 +1,1237 @@ +/*@z23.c:Galley Printer:ScaleFactor()@****************************************/ +/* */ +/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.17) */ +/* COPYRIGHT (C) 1991, 1999 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; + debug7(DGP, DD, "[ FixAndPrintObject(%s %s, %s, %s,%s, %s, %s, pg )", + 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")); + 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)); + debug7(DGP, DD, " calling SPAN %s(xmk %s, x %s,%s, cons %s, z %s,%s)", + dimen(dim), EchoLength(xmk), + EchoLength(back(x, dim)), EchoLength(fwd(x, dim)), + EchoConstraint(&constraint(y)), + EchoLength(back(z, dim)), EchoLength(fwd(z, dim))); + /* *** + f = find_max(xf, fwd(z,dim)); + FixAndPrintObject(z, xmk - back(thr, dim) + back(z, dim), back(z, dim), + find_max(f, bfc(constraint(y)) - back(z, dim)), + dim, FALSE, pg, 1); + *** */ + debug5(DGP, DD, " calling FAPO from %s (y = %s, bfc = %s, z = %s,%s", + Image(type(x)), Image(type(y)), EchoLength(bfc(constraint(y))), + EchoLength(back(z, dim)), EchoLength(fwd(z, dim))); + /* *** + FixAndPrintObject(z, xmk - back(thr, dim) + back(z, dim), back(z, dim), + bfc(constraint(y)) - back(z, dim), dim, FALSE, pg, 1); + *** */ + FixAndPrintObject(z, xmk - back(thr, dim) + back(z, dim), back(z, dim), + find_max(fwd(z, dim), bfc(constraint(y)) - back(z, dim)), + 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: + + /* nothing to print, spanner beneath is already done */ + 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_font; + 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' ) + { PrintWord(x, word_save_mark(x), pg - xmk); + if( underline(x) == UNDER_ON ) + { + FontWordSize(x); /* to restore fwd(x, COLM) */ + 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); + switch( BackEnd ) + { + case PLAINTEXT: + + break; + + + case POSTSCRIPT: + case PDF: + + if( dim == COLM ) + FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count); + else if( (scale_factor = ScaleFactor(xb+xf, size(y, ROWM))) > 0 ) + { SaveGraphicState(y); + CoordTranslate(0, pg-(xmk-xb+(FULL_LENGTH) (back(y,ROWM)*scale_factor))); + CoordScale(1.0, scale_factor); + FixAndPrintObject(y, 0, back(y,ROWM), fwd(y,ROWM), dim, + NO_SUPPRESS, 0, count); + RestoreGraphicState(); + } + else if( !is_word(type(y)) || string(y)[0] != '\0' ) + Error(23, 1, "object deleted (it cannot be scaled vertically)", + WARN, &fpos(x)); + break; + } + back(x, dim) = xb; fwd(x, dim) = xf; + break; + + + case HSCALE: + + debug0(DRS, DD, "FixAndPrintObject at HSCALE"); + CountChild(y, Down(x), count); + switch( BackEnd ) + { + case PLAINTEXT: + + break; + + + case POSTSCRIPT: + case PDF: + + 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 ) + { SaveGraphicState(y); + CoordTranslate(save_mark(x) - bc(constraint(x)) + + (FULL_LENGTH) (back(y, COLM)*scale_factor), 0); + CoordScale(scale_factor, 1.0); + FixAndPrintObject(y, xmk, xb, xf, dim, NO_SUPPRESS, pg, count); + RestoreGraphicState(); + } + break; + } + back(x, dim) = xb; fwd(x, dim) = xf; + break; + + + case SCALE: + + CountChild(y, Down(x), count); + switch( BackEnd ) + { + case PLAINTEXT: + + /* printable only if scale factor is one */ + if( bc(constraint(x)) == SF && fc(constraint(x)) == SF ) + { + FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count); + } + break; + + + case POSTSCRIPT: + case PDF: + + 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)); + SaveGraphicState(y); + CoordTranslate(save_mark(x), pg - xmk); + CoordScale( (float) bc(constraint(x))/SF, + (float) fc(constraint(x))/SF); + FixAndPrintObject(y, 0, yb, yf, dim, NO_SUPPRESS, + 0, count); + RestoreGraphicState(); + } + break; + } + 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); + switch( BackEnd ) + { + case PLAINTEXT: + + /* printable only if angle is zero */ + if( sparec(constraint(x)) == 0 ) + { + FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count); + } + break; + + + case POSTSCRIPT: + case PDF: + + 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; + SaveGraphicState(y); + CoordTranslate(save_mark(x), pg - xmk); + 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); + RestoreGraphicState(); + } + break; + } + back(x, dim) = xb; fwd(x, dim) = xf; + break; + + + case PLAIN_GRAPHIC: + + CountChild(y, LastDown(x), count); + switch( BackEnd ) + { + + case POSTSCRIPT: + case PDF: + + FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count); + break; + + + case PLAINTEXT: + + 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; + PrintPlainGraphicObject(pre, save_mark(x), + pg - (xmk - back(x, dim)), x); + FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count); + if( post != nilobj ) + PrintPlainGraphicObject(post, save_mark(x), + pg - (xmk - back(x, dim)), x); + } + break; + + } /* end switch */ + back(x, dim) = xb; fwd(x, dim) = xf; + break; + + + case GRAPHIC: + + CountChild(y, LastDown(x), count); + switch( BackEnd ) + { + case PLAINTEXT: + + FixAndPrintObject(y, xmk, xb, xf, dim, suppress, pg, count); + break; + + + case POSTSCRIPT: + case PDF: + + 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_font; + 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; + + SaveTranslateDefineSave(x, save_mark(x), pg - (xmk + fwd(x, ROWM))); + /* *** + SaveGraphicState(x); + CoordTranslate(save_mark(x), pg - (xmk + fwd(x, ROWM))); + debug4(DGP, DD, "GRAPHIC ROWM calling %s,%s %s,%s", + EchoLength(back(x, COLM)), EchoLength(fwd(x, COLM)), + EchoLength(back(x, ROWM)), EchoLength(fwd(x, ROWM))); + DefineGraphicNames(x); + SaveGraphicState(x); + *** */ + + PrintGraphicObject(pre); + RestoreGraphicState(); + FixAndPrintObject(y, xb, xb, xf, dim, NO_SUPPRESS, xb + xf, count); + if( post != nilobj ) PrintGraphicObject(post); + RestoreGraphicState(); + } + break; + + } /* end switch */ + back(x, dim) = xb; fwd(x, dim) = xf; + break; + + + case INCGRAPHIC: + case SINCGRAPHIC: + + CountChild(y, Down(x), count); + switch( BackEnd ) + { + case PLAINTEXT: + + break; + + + case POSTSCRIPT: + case PDF: + + 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_font; + 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) ) + PrintGraphicInclude(x, save_mark(x), pg - xmk); + break; + + } + 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) ) + { + 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; + + 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)); + + 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 != PLAINTEXT && 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; + 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)); + 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 */ + 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; + + + 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 */ |