/box-table-apply-colspans { % => MaxWC MinWC WidthFun Context Widths This dup box-table-get-colspans { % => MaxWC MinWC WidthFun Context Widths This Colspan dup cellspan-get-row 1 index cellspan-get-column 3 index box-table-get-cell % => MaxWC MinWC WidthFun Context Widths This Colspan Cell % apply colspans to the corresponsing colspanned-cell dimension 4 index 1 index 7 index call-method % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth % Apply cell constraint width, if any AND if table width is constrained % if table width is not constrained, we should not do this, as current value % of $table->get_width is maximal width (parent width), not the actual % width of the table 1 index get-width-constraint dup /type get /none ne { % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth WC 4 index /get-width call-method 2 index 2 index dup /apply get exec % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth WC CellWidth' exch pop exch pop } { pop } ifelse % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % now select the pre-calculated widths of columns covered by this cell % select the list of resizable columns covered by this cell [] [] % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' SpannedWidth SpannedRezisable 4 index cellspan-get-column 1 6 index cellspan-get-column 7 index cellspan-get-size add 1 sub { % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth SpannedRezisable I 7 index 1 index get % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth SpannedRezisable I Widths[i] 4 3 roll array-prepend 3 1 roll % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable I 11 index 1 index get % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable I MaxWC[i] 11 index 2 index get % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable I MaxWC[i] MinWC[i] ne % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable I MaxWC[i]<>MinWC[i] exch pop exch array-prepend % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' } for % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' % Sometimes we may encounter the colspan over the empty columns (I mean ALL columns are empty); in this case % we need to make these columns reizable in order to fit colspanned cell contents 1 index sum 0 eq { % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' 0 1 2 index length 1 sub { % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' I 2 index 1 index rounding-epsilon put 1 index 1 index true put pop } for } if % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' % The same problem may arise when all colspanned columns are not resizable; in this case we'll force all % of them to be resized { or } false 2 index reduce % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' AnyResizable not { 0 1 2 index length 1 sub { % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' I 1 index 1 index true put pop } for } if % => MaxWC MinWC WidthFun Context Widths This Colspan Cell CellWidth' % SpannedWidth' SpannedRezisable' % Expand resizable columns expand-to-with-flags % => MaxWC MinWC WidthFun Context Widths This Colspan Cell SpannedWidths' % Store modified widths 4 index 3 index cellspan-get-column 2 index putinterval % => MaxWC MinWC WidthFun Context Widths This Colspan Cell SpannedWidths' pop pop pop } forall % => MaxWC MinWC WidthFun Context Widths' This pop exch pop exch pop exch pop exch pop } def % => Widths /box-table-columns-fit { % => Context Width Table 2 index 1 index box-table-get-table-columns-min-widths % => Context Width Table MinW 3 index 2 index box-table-get-table-columns-max-widths % => Context Width Table MinW MaxW % Store number of columns dup length % => Context Width Table MinW MaxW Columns % Apply column width constraints [] [] % => Context Width Table MinW MaxW Columns MinWC MaxWC 0 1 4 index 1 sub { % => Context Width Table MinW MaxW Columns MinWC MaxWC I dup 7 index box-table-get-cwc % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC % Do not allow constrained max width be less than min width % Do not allow constrained min width be less than min width 7 index /get-width call-method % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth 8 index /cellpadding get-css-value 2 mul 9 index /cellspacing get-css-value add % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra 8 index 4 index get % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra MinW[i] 1 index sub 2 index 1 index 5 index dup /apply get exec % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra MinW[i] MinW[i]' 2 index add max % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra MinW[i]'' 7 6 roll array-prepend 6 1 roll % => Context Width Table MinW MaxW Columns MinWC' MaxWC I CWC ThisWidth Extra 8 index 4 index get % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra MinW[i] 1 index sub 2 index 1 index 5 index dup /apply get exec % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra MinW[i] MaxW[i]' 2 index add max % => Context Width Table MinW MaxW Columns MinWC MaxWC I CWC ThisWidth Extra MaxW[i]'' 6 5 roll array-prepend 5 1 roll % => Context Width Table MinW MaxW Columns MinWC MaxWC' I CWC ThisWidth Extra pop pop pop pop % => Context Width Table MinW MaxW Columns MinWC MaxWC } for 1 index 5 index 8 index 8 index box-table-normalize-min-widths % => Context Width Table MinW MaxW Columns MinWC MaxWC MinWC' 3 2 roll pop exch % => Context Width Table MinW MaxW Columns MinWC' MaxWC dup 2 index /get-min-width 10 index 5 index 10 index box-table-apply-colspans % => Context Width Table MinW MaxW Columns MinWC MaxWC MinWC' 3 2 roll pop exch % => Context Width Table MinW MaxW Columns MinWC' MaxWC % We need to normalize widths for the case of colspans width is too much; for example: %
%
TEXTTEXT
% in this case table SHOULD NOT be expanded over the 100px! 1 index 5 index 8 index 8 index box-table-normalize-min-widths % => Context Width Table MinW MaxW Columns MinWC' MaxWC MinWC' 3 2 roll pop exch dup 2 index /get-max-width 10 index 4 index 10 index box-table-apply-colspans % => Context Width Table MinW MaxW Columns MinWC MaxWC MaxWC' exch pop % => Context Width Table MinW MaxW Columns MinWC' MaxWC % Calculate actual widths % Calculate widths for all constrained columns [] 0 1 5 index 1 sub { % => Context Width Table MinW MaxW Columns MinWC' MaxWC Widths I dup 8 index box-table-is-constrained-column { 3 index exch get exch array-prepend % => Context Width Table MinW MaxW Columns MinWC' MaxWC Widths' } { % => Context Width Table MinW MaxW Columns MinWC' MaxWC Widths I pop 0 exch array-prepend % => Context Width Table MinW MaxW Columns MinWC' MaxWC Widths' } ifelse } for % => Context Width Table MinW MaxW Columns MinWC' MaxWC Widths' % Quick fix for overconstrained tables: if table have width attribute AND its value is less than sum % of constrained columns widths plus minimal widths of uncostrained columns, then we'll expand the width of table % to fit all columns % 1. calculate sum of constrained column widths % 2. calculate sum of unconstrained column minimal widths 0 0 % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW SumUCW 0 1 7 index 1 sub { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW SumUCW I dup 10 index box-table-is-constrained-column { 3 index 1 index get % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW SumUCW I W 4 3 roll add 3 1 roll % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW' SumUCW I } { 5 index 1 index get % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW SumUCW I CW 3 2 roll add exch % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW SumUCW' I } ifelse pop } for % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths SumCW SumUCW % 3. compare these widths with the table width and choose the maximal value add 8 index max % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths Width' 9 8 roll pop 8 1 roll % => Context Width' Table MinW MaxW Columns MinWC MaxWC Widths % Second pass - disctribute the rest of the width % Explanation of the stuff below (I've really had problems with this small piece of code, especially % when I was trying to fix "bugs" inside it) % % First of all, no column can be narrower than it minimal width (determined by its content) % Note that constrained columns have their widths distributed above, so we can exclude them for now % (just throw them out and imagine that table does not contain any width-constrained cols) % % Second, the relative widths of columns will have _appoximately_ the same ratio as % their maximal content widths. (In exception of cases where the first rule will take place - % say for the table containing two columns with the VERY long text in the first and one or two words % in the second) % % In general, this approach can be inoptimal in case of _very_ different font sizes % inside the cells, of, say big images; nevertheless, it will give a good approximate % AND still fast enough (unlike fully correct methods involving evaluation of the content height of the cell) % % Thus, we do the following: % - calculate the ratio of current column MAXIMAL ($current_max) width to the sum of MAXIMAL widths of all columns left % (inluding current) second rule applied. Note that we need remember about column spans and select % maxw or maxwc in order. % - then check if the rest of width will be too small for other columns to fit and decrease current columns % width (see MIN function call) % - then check again if our width will be too small for current column to fit (and expand if nesessary) - % MAX function call % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths 0 1 5 index 1 sub { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I dup 8 index box-table-is-constrained-column not { % Get undistributed width (total table width - width of constrained columns) 8 index 2 index sum sub % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest % get max width of column being processed % If width is equal to zero, use max constrained width, as this column could be covered by colspan; % If not, we lose nothing, because all constrained columns are already processed earlier, and no more % columns except these two types can have different constrained and raw widths 6 index 2 index get 4 index 3 index get max % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % Get sum of maximal constrained widths of unplaced columns 0 0 % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW 0 1 10 index 1 sub { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW J 6 index 1 index get 0 eq { 10 index 1 index get 8 index 2 index get max % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW J DSumMaxCW 4 3 roll add 3 1 roll % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW' SumMinCW J 11 index 1 index get 9 index 2 index get max % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW J DSumMinCW 3 2 roll add exch % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW' J } if % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW J pop } for % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW % If some unplaced columns have maximal (constrained width) greater zero 1 index 0 gt { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW 10 index 5 index get 8 index 6 index get max % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW max($minwc[$i],$minw[$i])) 1 index sub 4 index add % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW ($rest-$sum_min_cw+max($minwc[$i],$minw[$i])) 3 index 5 index mul 3 index div min % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I Rest CurrentMax % SumMaxCW SumMinCW CurrentMax' exch pop exch pop exch pop exch pop % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I CurrentMax' } { pop pop exch pop } ifelse % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I CurrentMax % Check for minimal width (either unconstrained or constrained) of current column 7 index 2 index get 0 eq { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I CurrentMax 4 index 2 index get } { 7 index 2 index get } ifelse max % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I CurrentMax' % Store calculated width 2 index exch 2 index exch put % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths' I } if % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I CurrentMax pop } for % => Context Width' Table MinW MaxW Columns MinWC MaxWC Widths % Process the case of a lone empty table cell (used, for example, for its background color) % as we're using floating point numbers, we cannot use equals sign dup sum rounding-epsilon lt { 0 1 2 index length 1 sub { % => Context Width' Table MinW MaxW Columns MinWC MaxWC Widths I 1 index exch % => Context Width' Table MinW MaxW Columns MinWC MaxWC I Widths rounding-epsilon put % => Context Width' Table MinW MaxW Columns MinWC MaxWC Widths } for } if % => Context Width' Table MinW MaxW Columns MinWC MaxWC Widths % now - the last attempt; if total width is less than box width, then we have a situation when either % all columns AND table are width constrained or the HTML similer to the following: % % % %
TEXT % % e.g. empty column (with zero width) and fixed-width column. dup sum 8 index lt { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths % Let's make zero-width columns % non-zero width (so that they columb expanded) and re-try expanding columns 0 1 2 index length 1 sub { % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths I 1 index 1 index get 0 eq { 1 index 1 index rounding-epsilon put } if pop } for % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths 7 index 1 index 8 index box-table-get-non-constrained-width-flags expand-to-with-flags % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths Widths' exch pop } if % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths % in case of overconstrained table (e.g. two columns with 20% widths), expand them 7 index 1 index expand-to exch pop % => Context Width Table MinW MaxW Columns MinWC MaxWC Widths' exch pop exch pop exch pop exch pop exch pop exch pop exch pop exch pop } def /box-table-column-widths { % => Context Table 1 index 1 index /get-width call-method 2 index box-table-columns-fit % => Context Table Widths exch pop exch pop } def /box-table-count-cols { get-content 0 get get-content length } def /box-table-count-rows { get-content length } def /box-table-create { % => box-container-create % => Box dup box-table-setup-methods dup /box-table add-type % List of column width constraints dup [] box-table-put-cwc-list dup [] box-table-put-rhc-list } def /box-table-fit-rowspans { % => Heights Table % Scan all cells spanning several rows dup box-table-get-rowspans % => Heights Table Rowspans { % => Heights Table Rowspan dup cellspan-get-row 1 index cellspan-get-column % => Heights Table Rowspan RsRow RsCol 3 index box-table-get-cell % => Heights Table Rowspan Cell % now check if cell height is less than sum of spanned rows heights 3 index 2 index cellspan-get-row 3 index cellspan-get-size getinterval % => Heights Table Rowspan Cell RowHeights sum % => Heights Table Rowspan Cell RowHeightsSum dup 2 index get-full-height gt { % Vertical-align current cell % calculate (approximate) row baseline 3 index get-content % => Heights Table Rowspan Cell RowHeightsSum Rows 3 index cellspan-get-row get % => Heights Table Rowspan Cell RowHeightsSum Row box-table-row-get-baseline % => Heights Table Rowspan Cell RowHeightsSum RowBaseline % apply vertical-align 1 index 3 index % => Heights Tablw Rowspan Cell RowHeightsSum Baseline RowHeightsSum Cell box-table-cell-apply-vertical-align % => Heights Tablw Rowspan Cell RowHeightsSum % Make cell fill all available vertical space dup 2 index put-full-height % => Heights Tablw Rowspan Cell RowHeightsSum } if % => Heights Table Rowspan Cell RowHeightsSum pop pop pop } forall % => Heights Table pop pop } def /box-table-get-cell { % => Y X Table dup get-content 3 index get % => Y X Table Row get-content 2 index get % => Y X Table Cell exch pop exch pop exch pop } def /box-table-get-colspans { % => Table [] 0 2 index get-content % => Table RS I Rows { % => Table RS I Row 1 index exch box-table-row-get-colspans % => Table RS I RowColSpans 3 2 roll exch % => Table I RS RowColSpans array-merge % => Table I RS' exch % => Table RS' I 1 add } forall pop exch pop } def /box-table-get-cwc { % => Index Table /CWC get exch get } def % Note that if table have no width constraint AND some columns are percentage constrained, % then the width of the table can be determined based on the minimal column width; % e.g. if some column have minimal width of 10px and 10% width constraint, % then table will have minimal width of 100px. If there's several percentage-constrained columns, % then we choose from the generated values the maximal one % % Of course, all of the above can be applied ONLY to table without width constraint; % of theres any w.c. applied to the table, it will have greater than column constraints % % We must take constrained table width into account; if there's a width constraint, % then we must choose the maximal value between the constrained width and sum of minimal % columns widths - so, expanding the constrained width in case it is not enough to fit % the table contents % % @param $context referene to a flow context object % @return minimal box width (including the padding/margin/border width! NOT content width) % /box-table-get-min-width { % => Context Table 1 index 1 index box-table-get-table-columns-min-widths % => Context Table Widths dup sum % => Context Table Widths Width dup % => Context Table Widths Width BaseWidth 3 index get-width-constraint /type get /none ne { % => Context Table Widths Width BaseWidth % Check if constrained table width should be expanded to fit the table contents 1 index % => Context Table Widths Width BaseWidth Width 5 index 5 index get-parent box-container-get-available-width % => Context Table Widths Width BaseWidth Width AvailWidth 0 6 index get-width-constraint dup /apply get exec % => Context Table Widths Width BaseWidth Width CWidth max % => Context Table Widths Width BaseWidth Width' 3 2 roll pop exch % => Context Table Widths Width' BaseWidth } { % => Context Table Widths Width BaseWidth % Now check if there's any percentage column width constraints (note that % if we've get here, than the table width is not constrained). Calculate % the table width basing on these values and select the maximal value 0 % => Context Table Widths Width BaseWidth I 3 index { % => Context Table Widths Width BaseWidth I Widths[i] 1 index 6 index box-table-get-cwc % => Context Table Widths Width BaseWidth I Widths[i] CWC 3 index exch % => Context Table Widths Width BaseWidth I Widths[i] BaseWidth CWC 2 index exch % => Context Table Widths Width BaseWidth I Widths[i] BaseWidth Width[i] CWC dup /apply-inverse get exec % => Context Table Widths Width BaseWidth I Widths[i] ICW 7 index 7 index get-parent box-container-get-available-width % => Context Table Widths Width BaseWidth I Widths[i] ICW AW 7 index get-hor-extra sub % => Context Table Widths Width BaseWidth I Widths[i] ICW AW-HE min % => Context Table Widths Width BaseWidth I Widths[i] min(ICW,AW-HE) 4 index max % => Context Table Widths Width BaseWidth I Widths[i] W 5 4 roll pop 4 1 roll % => Context Table Widths Width' BaseWidth I Widths[i] pop 1 add } forall % => Context Table Widths Width BaseWidth I pop } ifelse pop % => Context Table Widths Width 2 index get-hor-extra add % => Context Table Widths Width' exch pop exch pop exch pop } def /box-table-get-max-width { % => Context Table dup get-width-constraint /type get /none ne { % => Context Table % Check if constrained table width should be expanded to fit the table contents 1 index 1 index box-container-get-available-width % => COntext Table AvailableWidth 0 % => Context Table AvailableWidth 0 2 index get-width-constraint % => Context Table AvailableWidth 0 WC dup /apply get exec % => Context Table WC } { % => Context Table 2 copy box-table-get-table-columns-max-widths % => Context Table CMaxW 2 index 2 index box-table-get-table-columns-min-widths % => Context Table CMaxWs CMinWs 1 index 1 index /get-max-width % => Context Table CMaxWs CMinWs CMaxWs CMinWs /get-max-width 6 index % => Context Table CMaxWs CMinWs CMaxWs CMinWs /get-max-width Context 3 index % => Context Table CMaxWs CMinWs CMaxWs CMinWs /get-max-width Context CMaxWs 7 index box-table-apply-colspans % => Context Table CMaxWs CMinWs CMaxWs' exch pop exch pop % => Context Table Widths dup sum dup % => COntext Table Widths W BaseW % Now check if there's any percentage column width constraints (note that % if we've get here, than the table width is not constrained). Calculate % the table width basing on these values and select the maximal value 0 % => Context Table Widths Width BaseWidth I 3 index { % => Context Table Widths Width BaseWidth I Widths[i] 1 index 6 index box-table-get-cwc % => Context Table Widths Width BaseWidth I Widths[i] CWC 3 index exch % => Context Table Widths Width BaseWidth I Widths[i] BaseWidth CWC 2 index exch % => Context Table Widths Width BaseWidth I Widths[i] BaseWidth Width[i] CWC dup /apply-inverse get exec % => Context Table Widths Width BaseWidth I Widths[i] ICW 7 index 7 index get-parent box-container-get-available-width % => Context Table Widths Width BaseWidth I Widths[i] ICW AW 7 index get-hor-extra sub % => Context Table Widths Width BaseWidth I Widths[i] ICW AW-HE min % => Context Table Widths Width BaseWidth I Widths[i] min(ICW,AW-HE) 4 index max % => Context Table Widths Width BaseWidth I Widths[i] W 5 4 roll pop 4 1 roll % => Context Table Widths Width' BaseWidth I Widths[i] pop 1 add } forall % => Context Table Widths Width BaseWidth I pop pop exch pop % => Context Table Width } ifelse 1 index get-hor-extra add % => Context Table Width' exch pop exch pop } def % Get a list of boolean values indicating if table rows are NOT constant constrained % % @return array containing 'true' value at index I if I-th row is height-constrained % and 'false' otherwise % /box-table-get-non-constant-constrained-height-flags { [] % => Table Flags 0 1 3 index box-table-count-rows 1 sub { % => Table Flags I 2 index box-table-get-rhc % => Table Flags RHC hc-is-constant not % => Table Flags Flag exch array-prepend % => Table Flags' } for % => Table Flags exch pop % => Flags } def % Get a list of boolean values indicating if table rows are height constrained % % @return array containing 'true' value at index I if I-th row is not height-constrained % and 'false' otherwise % /box-table-get-non-constrained-flags { % => Table [] % => Table Flags 0 1 3 index box-table-count-rows 1 sub { % => Table Flags I 2 index box-table-get-rhc % => Table Flags RHC hc-is-null % => Table Flags Flag exch array-prepend % => Table Flags' } for % => Table Flags exch pop % => Flags } def % Get a list of boolean values indicating if table columns are height constrained % % @return array containing 'true' value at index I if I-th columns is not width-constrained % and 'false' otherwise % /box-table-get-non-constrained-width-flags { [] % => Table Flags 0 1 3 index box-table-count-cols 1 sub { % => Table Flags I 2 index box-table-get-cwc % => Table Flags CWC /type get /none eq exch array-prepend % => Table Flags' } for % => Table Flags exch pop % => Flags } def % Get a list of boolean values indicating if table rows are height constrained using percentage values % % @return array containing 'true' value at index I if I-th row is not height-constrained % and 'false' otherwise % /box-table-get-non-percentage-constrained-height-flags { [] % => Table Flags 0 1 3 index box-table-count-rows 1 sub { % => Table Flags I 2 index box-table-get-rhc % => Table Flags RHC hc-is-percentage not % => Table Flags Flag exch array-prepend % => Table Flags' } for % => Table Flags exch pop % => Flags } def /box-table-get-rhc { % => Index Table /RHC get exch get } def /box-table-get-rowspans { % => Table [] 0 2 index get-content % => Table RS I Rows { % => Table RS I Row 1 index exch box-table-row-get-rowspans % => Table RS I RowColSpans 3 2 roll exch % => Table I RS RowColSpans array-merge % => Table I RS' exch % => Table RS' I 1 add } forall % => Table RS I pop exch pop } def /box-table-get-table-columns-min-widths { % => Context Table [] % => Context Table Widths 1 index get-content 0 get get-content { % => Context Table Widths Cell pop 0 exch array-append } forall % => Context Table Widths 1 index get-content { % => Context Table Widths Row 3 index exch box-table-row-get-table-columns-min-widths { max } zip-with % => Context Table Widths' } forall % => Context Table Widths exch pop exch pop } def /box-table-get-table-columns-max-widths { % => Context Table [] % => Context Table Widths 1 index get-content 0 get get-content { % => Context Table Widths Cell pop 0 exch array-append } forall % => Context Table Widths 1 index get-content { % => Context Table Widths Row 3 index exch box-table-row-get-table-columns-max-widths { max } zip-with % => Context Table Widths' } forall % => Context Table Widths % Use column width constraints - column should not be wider its constrained width 0 1 2 index length 1 sub { % => Context Table Widths I dup 3 index box-table-get-cwc % => Context Table Widths I CWC % Newertheless, percentage constraints should not be applied IF table % does not have constrained width dup /type get /fraction eq not { % => Context Table Widths I CWC 3 index /get-width call-method 3 index 3 index get 2 index dup /apply get exec % => Context Table Widths I CWC W 3 index exch 3 index exch put % => Context Table Widths I CWC } if pop pop } for exch pop exch pop } def /box-table-get-width { % => Table dup get-parent /box-table-cell is-a not % => Table C1 1 index get-parent get-width-constraint /type get /none eq not % => Table C1 C2 2 index get-width-constraint /type get /fraction eq not % => Table C1 C2 C3 or or { dup get-parent /Position get /width get 1 index /Position get /width get 2 index get-width-constraint wc-apply % => Table W } { dup /Position get /width get } ifelse exch pop } def /box-table-have-colspan { % => Y X Table 3 copy box-table-get-cell % => Y X Table Cell box-table-cell-get-colspan exch pop exch pop exch pop } def /box-table-have-rowspan { % => Y X Table dup get-content % => Y X Table Rows 3 index get % => Y X Table Row 2 index get % => Y X Table Cell box-table-cell-get-rowspan exch pop exch pop exch pop } def /box-table-is-constrained-column { % => Index Table 2 copy box-table-get-cwc /type get /none ne exch pop exch pop } def % Tries to change minimal constrained width so that columns will fit into the given % table width % % Note that every width constraint have its own priority; first, the unconstrained columns are collapsed, % then - percentage constrained and after all - columns having fixed width % % @param $width table width % @param $minw array of unconstrained minimal widths % @param $minwc array of constrained minimal widths % @return list of normalized minimal constrained widths % /box-table-normalize-min-widths { % => MinWC MinW Width Table % Check if sum of constrained widths is too big % Note that we compare sum of constrained width with the MAXIMAL value of table width and % sum of uncostrained minimal width; it will prevent from unneeded collapsing of table cells % if table content will expand its width anyway 2 index sum 2 index max % => MinWC MinW Width Table TWidth % compare with sum of minimal constrained widths 4 index sum 1 index gt { 4 index sum 1 index sub % => MinWC MinW Width Table TWidth Delta % Calculate the amount of difference between minimal and constrained minimal width for each columns 5 index 5 index { sub } zip-with % => MinWC MinW Width Table TWidth Delta Diff % If no difference is found, we can collapse no columns % otherwise scale some columns... dup sum % => MinWC MinW Width Table TWidth Delta Diff CWDelta dup 0 gt { % => MinWC MinW Width Table TWidth Delta Diff CWDelta 0 1 3 index length 1 sub { % => MinWC MinW Width Table TWidth Delta Diff CWDelta I 2 index 1 index get neg % => MinWC MinW Width Table TWidth Delta Diff CWDelta I -diff[i] 2 index div % => MinWC MinW Width Table TWidth Delta Diff CWDelta I -diff[i]/cwdelta 4 index mul % => MinWC MinW Width Table TWidth Delta Diff CWDelta I -diff[i]/cwdelta*delta 9 index 2 index get add % => MinWC MinW Width Table TWidth Delta Diff CWDelta I MinWC[i]' 9 index exch 2 index exch put % => MinWC MinW Width Table TWidth Delta Diff CWDelta I pop % => MinWC MinW Width Table TWidth Delta Diff CWDelta } for } if % => MinWC MinW Width Table TWidth Delta Diff CWDelta pop pop pop } if % => MinWC MinW Width Table TWidth pop pop pop pop % => MinWC } def /box-table-put-cwc-list { % => Box List /CWC exch put } def /box-table-put-rhc-list { % => Box List /RHC exch put } def /box-table-reflow { % => Context Parent This dup /float get-css-value /none eq { 3 copy box-table-reflow-static-normal } { 3 copy box-container-reflow-static-float } ifelse pop pop pop } def /box-table-reflow-content { % => Context This % Reset current Y value dup get-top 1 index put-current-y % Determine the base table width % if width constraint exists, the actual table width will not be changed anyway dup /get-width call-method 2 index 2 index /get-max-width call-method min 1 index put-width % calculate width of table columns 2 copy box-table-column-widths % => Context This ColWidths % Collapse table to minimum width (if width is not constrained dup sum 2 index put-width % => Context This ColWidths % Flow cells horizontally in each table row 0 1 3 index box-table-count-rows 1 sub { % => Context This ColWidths I % Row flow started % Reset current X coordinate to the far left of the table 2 index get-left 3 index put-current-x % Flow each cell in the row 0 % => Context This ColWidths I Span 0 1 5 index box-table-count-cols 1 sub { % => Context This ColWidths I Span J % Skip cells covered by colspans (fake cells, anyway) 1 index 0 eq { % => Context This ColWidths I Span J % Flow current cell % Any colspans here? 2 index 1 index 6 index box-table-have-colspan % => COntext This ColWidths I Span J Span' 3 2 roll pop exch % => COntext This ColWidths I Span' J % Get sum of width for the current cell (or several cells in colspan) % In most cases, $span == 1 here (just a single cell) 3 index 1 index 3 index getinterval sum % => COntext This ColWidths I Span' J CW % store calculated width of the current cell 3 index 2 index % => Context This ColWidths I Span J CW I(Row) J(Col) 7 index box-table-get-cell % => COntext This ColWidths I Span J CW Cell 1 index 1 index put-full-width % => COntext This ColWidths I Span J CW Cell 1 index 1 index get-hor-extra sub wc-create-constant 1 index put-width-constraint % => COntext This ColWidths I Span' J CW Cell % Flow cell 7 index 7 index 2 index /reflow call-method % => COntext This ColWidths I Span' J CW Cell 6 index get-current-x 2 index add 7 index put-current-x % => COntext This ColWidths I Span' J CW Cell pop pop } if % => Context This ColWidths I SPan J pop % => Context This ColWidths I SPan % Current cell have been processed or skipped 1 sub 0 max } for % => Context This ColWidths I SPan pop % => Context This ColWidths I % row height calculation offset current Y coordinate by the row height calculated 2 index get-content 1 index get % => Context This ColWidth I Row box-table-row-height % => Context This ColWidth I RH 3 index get-current-y exch sub 3 index put-current-y % => Context This ColWidth I pop } for % => Context This ColWidths pop % => Context This % Calculate (and possibly adjust height of table rows) 0.1 1 index box-table-row-heights % => Context This RowHeights % adjust row heights to fit cells spanning several rows 1 index box-table-get-rowspans { % => Context This RowHeights Rowspan % Get height of the cell dup cellspan-get-row 1 index cellspan-get-column 4 index box-table-get-cell get-full-height % => Context This RowHeights Rowspan CellHeight % Get calculated height of the spanned-over rows 2 index 2 index cellspan-get-row 3 index cellspan-get-size getinterval % => Context This RowHeights Rowspan CellHeight CellRowHeights % Get list of non-constrained columns 4 index box-table-get-non-constrained-flags 3 index cellspan-get-row 4 index cellspan-get-size getinterval % => Context This RowHeights Rowspan CellHeight CellRowHeights Flags % Expand row heights (only for non-constrained columns) 3 copy expand-to-with-flags % => Context This RowHeights Rowspan CellHeight CellRowHeights Flags NewHeights exch pop % => Context This RowHeights Rowspan CellHeight CellRowHeights NewHeights % Check if rows could not be expanded dup sum 3 index rounding-epsilon sub lt { % => Context This RowHeights Rowspan CellHeight CellRowHeights NewHeights pop % Get list of non-constant-constrained columns 4 index box-table-get-non-constant-constrained-flags 3 index cellspan-get-row 4 index cellspan-get-size getinterval % => Context This RowHeights Rowspan CellHeight CellRowHeights Flags 3 copy expand-to-with-flags % => Context This RowHeights Rowspan CellHeight CellRowHeights Flags NewHeights exch pop % => Context This RowHeights Rowspan CellHeight CellRowHeights NewHeights } if % => Context This RowHeights Rowspan CellHeight CellRowHeights NewHeights % Update the rows heights 4 index 4 index cellspan-get-row 2 index putinterval % => Context This RowHeights Rowspan CellHeight CellRowHeights NewHeights pop pop pop pop } forall % => Context This RowHeights % Now expand rows to full table height dup sum 2 index get-height max % => Context This RowHeights TableHeight % Get list of non-constrained coluns 2 index box-table-get-non-constrained-flags 1 index exch 3 index exch expand-to-with-flags % => Context This RowHeights TableHeight RowHeights' 3 2 roll pop exch % => Context This RowHeights' TableHeight % Check if rows could not be expanded 1 index sum 1 index rounding-epsilon sub % => Context This RowHeights' TableHeight lt { % Get list of non-constant-constrained columns 2 index box-table-get-non-constant-constrained-flags % use non-constant-constrained rows 2 index exch expand-to-with-flags % => Context This RowHeights' TableHeight } if % => Context This RowHeights' TableHeight pop % Now we calculated row heights, time to actually resize them dup 2 index box-table-resize-rows % => Context This RowHeights % Update size of cells spanning several rows dup 2 index box-table-fit-rowspans % => Context This Rowheights pop pop pop } def /box-table-reflow-static-normal { % => Context Parent This % Calculate margin values if they have been set as a percentage 1 index 1 index box-generic-calc-percentage-margins % Calculate width value if it had been set as a percentage 3 copy box-generic-calc-percentage-width % As table width can be deterimined by its contents, we may calculate auto values % only AFTER the contents have been reflown; thus, we'll offset the table % as a whole by a value of left margin AFTER the content reflow % Do margin collapsing 3 copy box-generic-collapse-margin % => Context Parent This Y % At this moment we have top parent/child collapsed margin at the top of context object % margin stack 3 index exch 2 index box-generic-apply-clear % Store calculated Y coordinate as current Y in the parent box 2 index put-current-y % => Context Parent This % Terminate current parent line-box 2 index 2 index box-container-close-line % And add current box to the parent's line-box (alone) dup 2 index box-container-append-line % => Context Parent This % Determine upper-left _content_ corner position of current box % Also see note above regarding margins 1 index get-current-x 1 index get-border-left-width add 1 index get-padding-left add 1 index put-left % => Context Pareht This % Note that top margin already used above during maring collapsing 1 index get-current-y 1 index get-border-top-width sub 1 index get-padding-top sub 1 index put-top % => Context Parent This % By default, child block box will fill all available parent width; % note that actual width will be smaller because of non-zero padding, border and margins 2 index 2 index box-container-get-available-width 1 index put-full-width % => Context Parent This % reflow contents 2 index 1 index box-table-reflow-content % => Context Parent This % Update the collapsed margin value with current box bottom margin 2 index context-pop-collapsed-margin 2 index context-pop-collapsed-margin dup get-margin-bottom 3 index context-push-collapsed-margin % Calculate margins and/or width is 'auto' values have been specified 2 copy box-generic-calc-auto-width-margins 0 1 index get-margin-left 2 index /offset call-method % Extend parent's height to fit current box dup get-bottom-margin 2 index box-generic-extend-height % terminate parent's line box 2 index 2 index box-container-close-line % => Context Parent This pop pop pop } def /box-table-resize-rows { % => Heights Table dup get-top % => Heights Table RowTop 0 % => Heights Table RowTop I 2 index get-content { % => Heights Table RowTop I Row 4 index 2 index get % => Heights Table RowTop I Row H[I] 3 index % => Heights Table RowTop I Row H[I] RowTop 1 index % => Heights Table RowTop I Row H[I] RowTop H[I] 3 index % => Heights Table RowTop I Row H[i] RowTop H[I] Row box-table-row-resize % => Heights Table RowTop I Row H[i] exch pop % => Heights Table RowTop I H[i] 3 2 roll exch sub exch % => Heights Table RowTop' I 1 add % => Heights Table RowTop I+1 } forall % => Heights Table RowTop I pop pop 1 index sum 1 index put-height pop pop % => } def % Calculate set of row heights % % @param $minheight the minimal allowed height of the row; as we'll need to expand rows later % and rows containing totally empty cells will have zero height % @return array of row heights in media points % /box-table-row-heights { % => Minheight Box [] [] 0 % => Minheight Box Heights CHeights I 3 index get-content { % => Minheight Box Heights CHeights I Row box-table-row-height % => Minheight Box Heights CHeights I RowHeight 5 index max % => Minheight Box Heights CHeights I RowHeight' dup % => Minheight Box Heights CHeights I RowHeight RowHeight 5 4 roll % => Minheight Box CHeights I RowHeight RowHeight Heights array-prepend % => Minheight Box CHeights I RowHeight Heights' 4 1 roll % => Minheight Box Heights' CHeights I RowHeight 1 index 5 index box-table-get-rhc % => Minheight Box Heights' CHeights I RowHeight RHC 5 index get-content 3 index get exch % => Minheight Box Heights' CHeights I RowHeight RHC Cell 2 index exch hc-apply % => Minheight Box Heights' CHeights I RowHeight RowHeightC 4 3 roll % => Minheight Box Heights' I RowHeight RowHeightC CHeights array-prepend % => Minheight Box Heights' I RowHeight CHeights' 3 1 roll % => Minheight Box Heights' CHeights' I RowHeight pop 1 add % => Minheight Box Heights' CHeights' I+1 } forall pop % => Minheight Box Heights' CHeights' % Now adjust percentage-constrained rows; 2 index box-table-get-non-percentage-constrained-height-flags % => Minheight Box Heights CHeights Flags 3 index get-height % => Minheight Box Heights CHeights Flags H CH 0 0 % => Minheight Box Heights CHeights Flags H CH I 3 index { % => Minheight Box Heights CHeights Flags H CH I Flag { % => Minheight Box Heights CHeights Flags H CH I 4 index 1 index get % => Minheight Box Heights CHeights Flags H CH I CH[i] 4 3 roll exch sub % => Minheight Box Heights CHeights Flags CH I H' 3 1 roll % => Minheight Box Heights CHeights Flags H' CH I } { % => Minheight Box Heights CHeights Flags H CH I 4 index 1 index get % => Minheight Box Heights CHeights Flags H CH I CH[i] 3 2 roll add % => Minheight Box Heights CHeights Flags H I CH' exch % => Minheight Box Heights CHeights Flags H CH' I } ifelse 1 add } forall pop % => Minheight Box Heights CHeights Flags H CH' dup 0 gt { div % => Minheight Box Heights CHeights Flags Scale 0 % => Minheight Box Heights CHeights Flags Scale I 2 index % => Minheight Box Heights CHeights Flags Scale I Flags { % => Minheight Box Heights CHeights Flags Scale I Flag { % => Minheight Box Heights CHeights Flags Scale I 3 index 1 index get % => Minheight Box Heights CHeights Flags Scale I CH[i] 2 index mul % => Minheight Box Heights CHeights Flags Scale I CH[i]' 4 index exch % => Minheight Box Heights CHeights Flags Scale I CH CH[i]' 2 index exch % => Minheight Box Heights CHeights Flags Scale I CH I CH[i]' put % => Minheight Box Heights CHeights Flags Scale I } if 1 add % => Minheight Box Heights CHeights Flags Scale I+1 } forall pop pop pop } { pop pop pop } ifelse % => Minheight Box Heights CHeights { max } zip-with % => Minheight Box Heights' exch pop exch pop } def /box-table-setup-methods { % => Box dup get-box-dict /Methods get dup /reflow {box-table-reflow} put dup /get-min-width {box-table-get-min-width} put dup /get-max-width {box-table-get-max-width} put dup /get-width {box-table-get-width} put dup /reflow-content {box-table-reflow-content} put pop pop } def % =>