1 /************************************************************************/
2 /*									*/
3 /*  Layout of a table row in the document.				*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docLayoutConfig.h"
8 
9 #   include	<stddef.h>
10 
11 #   include	"docLayout.h"
12 #   include	<docTreeType.h>
13 #   include	<docTreeNode.h>
14 #   include	"docRowLayout.h"
15 #   include	<docDebug.h>
16 
17 #   include	<appDebugon.h>
18 
19 /************************************************************************/
20 /*									*/
21 /*  Shift cell contents of the cells in a row that are not top-aligned.	*/
22 /*									*/
23 /************************************************************************/
24 
docLayoutRowValignCells(BufferItem * rowNode,BlockFrame * bf,const LayoutPosition * lpHere,const ParagraphLayoutPosition * rowPlp,const LayoutJob * lj)25 static int docLayoutRowValignCells(
26 				BufferItem *			rowNode,
27 				BlockFrame *			bf,
28 				const LayoutPosition *		lpHere,
29 				const ParagraphLayoutPosition *	rowPlp,
30 				const LayoutJob *		lj )
31     {
32     int				col;
33     const CellProperties *	cp= rowNode->biRowCells;
34     const ParagraphLayoutJob *	plj;
35 
36     cp= rowNode->biRowCells;
37     plj= rowPlp->pspChildren;
38     for ( col= 0; col < rowNode->biChildCount; cp++, plj++, col++ )
39 	{
40 	const CellProperties *	thisCp= cp;
41 	BufferItem *		cellNode= rowNode->biChildren[col];
42 	int			rowTop= rowNode->biTopPosition.lpPageYTwips;
43 	int			rowHigh;
44 	int			cellHigh;
45 
46 	int			paraFrom= 0;
47 	int			paraUpto= cellNode->biChildCount;
48 
49 	LayoutPosition		lpTop;
50 
51 	if  ( cellNode->biCellRowspan > 1 )
52 	    { continue;	}
53 
54 	if  ( cp->cpVerticalMerge == CELLmergeFOLLOW )
55 	    {
56 	    if  ( cellNode->biCellMergedCellTopRow < 0	)
57 		{ continue;	}
58 	    else{
59 		BufferItem *	topRowNode;
60 
61 		int		topRow= cellNode->biCellMergedCellTopRow;
62 		int		topCol= cellNode->biCellMergedCellTopCol;
63 
64 		topRowNode= rowNode->biParent->biChildren[topRow];
65 		rowTop= topRowNode->biTopPosition.lpPageYTwips;
66 		cellNode= topRowNode->biChildren[topCol];
67 		thisCp= topRowNode->biRowCells+ topCol;
68 		}
69 	    }
70 
71 	lpTop= cellNode->biTopPosition;
72 	rowHigh= lpHere->lpPageYTwips- rowTop;
73 	cellHigh= cellNode->biBelowPosition.lpPageYTwips-
74 				    cellNode->biTopPosition.lpPageYTwips;
75 
76 	if  ( cellHigh >= rowHigh )
77 	    { continue;	}
78 
79 	switch( thisCp->cpValign )
80 	    {
81 	    case DOCtvaTOP:
82 		continue;
83 
84 	    case DOCtvaCENTERED:
85 		cellNode->biCellTopInset= ( rowHigh- cellHigh )/ 2;
86 		lpTop.lpPageYTwips += cellNode->biCellTopInset;
87 
88 		docRedoParaStripLayout( lj, bf, &lpTop,
89 						cellNode, paraFrom, paraUpto );
90 		continue;
91 
92 	    case DOCtvaBOTTOM:
93 		cellNode->biCellTopInset= rowHigh- cellHigh;
94 		lpTop.lpPageYTwips += cellNode->biCellTopInset;
95 
96 		docRedoParaStripLayout( lj, bf, &lpTop,
97 						cellNode, paraFrom, paraUpto );
98 		continue;
99 
100 	    default:
101 		LLDEB(col,thisCp->cpValign);
102 		continue;
103 	    }
104 	}
105 
106     return 0;
107     }
108 
109 /************************************************************************/
110 /*									*/
111 /*  Finish row layout.							*/
112 /*									*/
113 /*  1)  The bottom is below all cells.					*/
114 /*  2)  If there is a bottom inset, step over it.			*/
115 /*  3)  Stretch height to the minimum height (If any)			*/
116 /*  4)  Stretch height to the exact given height (If any)		*/
117 /*  5)  Fix the current position if a fixed-height row exceeds its	*/
118 /*	fixed height.							*/
119 /*									*/
120 /************************************************************************/
121 
docLayoutFinishRow(LayoutPosition * lpHere,BufferItem * rowNode,BlockFrame * bf,const LayoutJob * lj,ParagraphLayoutPosition * rowPlp)122 static void docLayoutFinishRow(	LayoutPosition *		lpHere,
123 				BufferItem *			rowNode,
124 				BlockFrame *			bf,
125 				const LayoutJob *		lj,
126 				ParagraphLayoutPosition *	rowPlp )
127     {
128     int				col;
129     CellProperties *		cp;
130     ParagraphLayoutJob *	plj;
131 
132     /*  1  */
133     cp= rowNode->biRowCells;
134     plj= rowPlp->pspChildren;
135     for ( col= 0; col < rowNode->biChildCount; cp++, plj++, col++ )
136 	{
137 	BufferItem *			cellNode= rowNode->biChildren[col];
138 	ParagraphLayoutPosition *	plp= &(plj->pljPos);
139 
140 	if  ( cp->cpVerticalMerge == CELLmergeFOLLOW		&&
141 	      cellNode->biCellMergedCellTopRow >= 0		)
142 	    {
143 	    docLayoutPushBottomDown( &(rowNode->biRowBelowAllCellsPosition),
144 					&(plj->cljMergedCellBelowPosion) );
145 	    docLayoutPushBottomDown( lpHere,
146 					&(plj->cljMergedCellBelowPosion) );
147 	    continue;
148 	    }
149 
150 	if  ( CELL_MERGED( cp ) )
151 	    { continue;	}
152 
153 	cellNode->biBelowPosition= plp->plpPos;
154 
155 	docLayoutPushBottomDown(
156 		    &(rowNode->biRowBelowAllCellsPosition), &(plp->plpPos) );
157 
158 	if  ( cellNode->biCellRowspan <= 1 )
159 	    { docLayoutPushBottomDown( lpHere, &(plp->plpPos) ); }
160 	}
161 
162     if  ( DOC_SAME_FRAME( lpHere, &(rowNode->biTopPosition) ) )
163 	{
164 	int		rowHeightTwips;
165 
166 	rowHeightTwips= lpHere->lpPageYTwips-
167 				    rowNode->biTopPosition.lpPageYTwips;
168 
169 	/*  3: if rowNode->biRowHeightTwips > 0   */
170 	if  ( rowHeightTwips < rowNode->biRowHeightTwips )
171 	    {
172 	    lpHere->lpPageYTwips +=  rowNode->biRowHeightTwips- rowHeightTwips;
173 	    lpHere->lpAtTopOfColumn= 0;
174 	    }
175 
176 	/*  4: if rowNode->biRowHeightTwips < 0  */
177 	if  ( rowHeightTwips < -rowNode->biRowHeightTwips )
178 	    {
179 	    lpHere->lpPageYTwips += -rowNode->biRowHeightTwips- rowHeightTwips;
180 	    lpHere->lpAtTopOfColumn= 0;
181 	    }
182 
183 	/*  5  */
184 	if  ( rowNode->biRowHeightTwips < 0			&&
185 	      rowHeightTwips > -rowNode->biRowHeightTwips	)
186 	    {
187 	    /* LLDEB(rowNode->biRowHeightTwips,rowHeightTwips); */
188 	    lpHere->lpPageYTwips -= rowHeightTwips+ rowNode->biRowHeightTwips;
189 	    }
190 
191 	if  ( docLayoutRowValignCells( rowNode, bf, lpHere, rowPlp, lj ) )
192 	    { LDEB(1);	}
193 	}
194 
195     docLayoutPushBottomDown( &(rowNode->biRowBelowAllCellsPosition), lpHere );
196 
197     return;
198     }
199 
200 /************************************************************************/
201 /*									*/
202 /*  Layout as much of a table row as fits on the current page.		*/
203 /*									*/
204 /*  1)  For a fixed height row, determine the amount of space left for	*/
205 /*	it.								*/
206 /*  2)  For all columns in the table..					*/
207 /*  3)  Cells in a row span or a colspan play no role...		*/
208 /*  4)  This column was already exhausted on a previous page..		*/
209 /*  5)  Format paragraphs inside this cell.				*/
210 /*  6)  Remember how far we have descended on the page.			*/
211 /*  7)  Anything left over that must be moved to the next page?		*/
212 /*  7a) Distinguish between the situation where a fixed height row has	*/
213 /*	reached its capacity and that where the page is full.		*/
214 /*									*/
215 /************************************************************************/
216 
docLayoutRowPageStrip(LayoutPosition * lpHere,int * pToNextColumn,int * pSomeAtHead,BufferItem * rowNode,ParagraphLayoutPosition * rowPlp,BlockFrame * bf,const LayoutJob * lj)217 static int docLayoutRowPageStrip(
218 			    LayoutPosition *		lpHere,
219 			    int *			pToNextColumn,
220 			    int *			pSomeAtHead,
221 			    BufferItem *		rowNode,
222 			    ParagraphLayoutPosition *	rowPlp,
223 			    BlockFrame *		bf,
224 			    const LayoutJob *		lj )
225     {
226     int				col;
227 
228     int				continueInNextFrame= 0;
229     int				someAtHead= 0;
230 
231     LayoutPosition		lpBottom;
232     const CellProperties *	cp;
233     ParagraphLayoutJob *	plj;
234 
235     lpBottom= *lpHere;
236 
237     continueInNextFrame= 0;
238 
239     if  ( rowPlp->pspChildCount != rowNode->biChildCount )
240 	{ LLDEB(rowPlp->pspChildCount,rowNode->biChildCount); return -1; }
241 
242     /*  1  */
243 
244     /*  2  */
245     cp= rowNode->biRowCells;
246     plj= rowPlp->pspChildren;
247     for ( col= 0; col < rowNode->biChildCount; cp++, plj++, col++ )
248 	{
249 	BufferItem *			cellNode= rowNode->biChildren[col];
250 	ParagraphLayoutPosition *	plp= &(plj->pljPos);
251 	int				stopCode= FORMATstopREADY;
252 
253 	/*  3  */
254 	if  ( CELL_MERGED( cp ) )
255 	    { continue;	}
256 
257 	/*  4  */
258 	if  ( docLayoutStripDone( plp, plj ) )
259 	    { continue;	}
260 
261 	/*  5  */
262 	plp->plpPos= *lpHere;
263 
264 	docCellStripFrame( cellNode, bf, plj );
265 
266 	if  ( docLayoutStripChildren( &stopCode, plj, bf, lj, cellNode ) )
267 	    { LDEB(1); return -1;	}
268 
269 	/*  6  */
270 	docLayoutPushBottomDown(
271 		    &(rowNode->biRowBelowAllCellsPosition), &(plp->plpPos) );
272 	if  ( cellNode->biCellRowspan <= 1 )
273 	    { docLayoutPushBottomDown( &lpBottom, &(plp->plpPos) );	}
274 
275 	/*  7,7a  */
276 	if  ( cellNode->biTreeType == DOCinBODY		&&
277 	      stopCode == FORMATstopBLOCK_FULL		)
278 	    { continueInNextFrame= 1;	}
279 	}
280 
281     cp= rowNode->biRowCells;
282     plj= rowPlp->pspChildren;
283     for ( col= 0; col < rowNode->biChildCount; cp++, plj++, col++ )
284 	{
285 	const ParagraphLayoutPosition *	plp= &(plj->pljPos);
286 
287 	if  ( docLayoutAtStripHead( &(plj->pljPos) ) )
288 	    {
289 	    if  ( ! docLayoutStripDone( plp, plj ) )
290 		{ someAtHead= 1;	}
291 	    }
292 	else{ rowPlp->pspChildAdvanced= 1;	}
293 	}
294 
295     *lpHere= lpBottom;
296     *pToNextColumn= continueInNextFrame;
297     *pSomeAtHead= someAtHead;
298 
299     if  ( ! continueInNextFrame )
300 	{ docLayoutFinishRow( lpHere, rowNode, bf, lj, rowPlp );	}
301 
302     return 0;
303     }
304 
305 /************************************************************************/
306 
docLayoutStartRowCells(BufferItem * rowNode,const BufferDocument * bd,const LayoutPosition * lpHere,const BlockFrame * bf,ParagraphLayoutPosition * rowPlp)307 static int docLayoutStartRowCells(
308 				BufferItem *			rowNode,
309 				const BufferDocument *		bd,
310 				const LayoutPosition *		lpHere,
311 				const BlockFrame *		bf,
312 				ParagraphLayoutPosition *	rowPlp )
313     {
314     CellProperties *		cp;
315     int				col;
316     int				l, r;
317     ParagraphLayoutJob *	cellPlj;
318 
319     int				nextRow= rowNode->biNumberInParent+ 1;
320     const BufferItem *		nextRowBi= (const BufferItem *)0;
321 
322     if  ( nextRow < rowNode->biRowTablePast )
323 	{ nextRowBi= rowNode->biParent->biChildren[nextRow]; }
324 
325     rowNode->biRowBelowAllCellsPosition= *lpHere;
326 
327     /*  2  */
328     cellPlj= rowPlp->pspChildren;
329     r= rowNode->biRowLeftIndentTwips;
330     cp= rowNode->biRowCells;
331     for ( col= 0; col < rowNode->biChildCount; cp++, cellPlj++, col++ )
332 	{
333 	BufferItem *	cellNode= rowNode->biChildren[col];
334 	const int	para= 0;
335 	const int	line= 0;
336 	const int	part= 0;
337 	int		colspan= 1;
338 
339 	const int	recursively= 0;
340 
341 	docDelimitTables( cellNode, recursively );
342 
343 	cellNode->biCellTopInset= 0;
344 
345 	docBeginParagraphLayoutProgress( cellPlj, para, line, part,
346 					    cellNode->biChildCount, lpHere );
347 
348 	cellNode->biTopPosition= *lpHere;
349 
350 	l= r; r= cp->cpRightBoundaryTwips;
351 	if  ( cp->cpHorizontalMerge == CELLmergeHEAD )
352 	    { r= docGetCellRight( &colspan, cellNode );	}
353 
354 	/*  3  */
355 	cellNode->biCellRowspan= 1;
356 	if  ( cp->cpVerticalMerge != CELLmergeNONE )
357 	    {
358 	    docRowLayoutRowspanAdmin( cellNode, rowNode, nextRowBi, nextRow,
359 							cp, l, r, cellPlj );
360 	    }
361 
362 	cp += colspan- 1;
363 	cellPlj += colspan- 1;
364 	col += colspan- 1;
365 	}
366 
367     return 0;
368     }
369 
370 /************************************************************************/
371 /*									*/
372 /*  Calculate the layout of a row in the document.			*/
373 /*									*/
374 /*  1)  Do not advance by row top inset. This is done between the top	*/
375 /*	of the paragraph and its first line. [This is what MS-Word	*/
376 /*	does.]								*/
377 /*  2)  Begin formatting.						*/
378 /*  3)  Keep track of the rowspan of the cells.				*/
379 /*									*/
380 /************************************************************************/
381 
docLayoutStartRow(int * pToNextColumn,BufferItem * rowNode,const BufferDocument * bd,LayoutPosition * lpHere,const BlockFrame * bf,ParagraphLayoutPosition * rowPlp)382 static int docLayoutStartRow(	int *				pToNextColumn,
383 				BufferItem *			rowNode,
384 				const BufferDocument *		bd,
385 				LayoutPosition *		lpHere,
386 				const BlockFrame *		bf,
387 				ParagraphLayoutPosition *	rowPlp )
388     {
389     const int			atRowTop= 1;
390 
391     int				minHeightTwips= rowNode->biRowHeightTwips;
392 
393     if  ( docParagraphLayoutPosClaimChildren( rowPlp, rowNode->biChildCount ) )
394 	{ LDEB(rowNode->biChildCount); return -1;	}
395 
396     if  ( rowNode->biRowHeightTwips < 0 )
397 	{ minHeightTwips= -rowNode->biRowHeightTwips;	}
398 
399     /*  3a  */
400     if  ( lpHere->lpPageYTwips+ minHeightTwips > bf->bfFlowRect.drY1	&&
401 	  ! lpHere->lpAtTopOfColumn					)
402 	{ *pToNextColumn= 1; return 0;	}
403 
404     rowNode->biRowAboveHeaderPosition= rowNode->biTopPosition;
405     rowNode->biRowPrecededByHeader= 0;
406 
407     /*  1  */
408     /*  NO! lpHere->lpPageYTwips += rowNode->biRowTopInset; */
409 
410     {
411     int rti= rowNode->biRowTopInset;
412     docLayoutCalculateRowTopInset( &rti, bd, rowNode, atRowTop );
413     rowNode->biRowTopInset= rti;
414     }
415 
416     if  ( docLayoutStartRowCells( rowNode, bd, lpHere, bf, rowPlp ) )
417 	{ LDEB(1); return -1;	}
418 
419     *pToNextColumn= 0;
420     return 0;
421     }
422 
423 /************************************************************************/
424 /*									*/
425 /*  Reserve space for a table header.					*/
426 /*									*/
427 /************************************************************************/
428 
docLayoutRowSkipHeaderHeight(LayoutPosition * lp,BufferItem * rowNode,int atTopOfRow)429 static void docLayoutRowSkipHeaderHeight( LayoutPosition *	lp,
430 					BufferItem *		rowNode,
431 					int			atTopOfRow )
432     {
433     const BufferItem *	headerBi;
434     int			headerHeight;
435 
436     if  ( rowNode->biRowTableHeaderRow < 0 )
437 	{ LDEB(rowNode->biRowTableHeaderRow); return;	}
438     if  ( rowNode->biRowIsTableHeader )
439 	{ LDEB(rowNode->biRowIsTableHeader); return;	}
440 
441     headerBi= rowNode->biParent->biChildren[rowNode->biRowTableHeaderRow];
442     if  ( ! headerBi->biRowIsTableHeader )
443 	{ LDEB(headerBi->biRowIsTableHeader);	}
444 
445     if  ( headerBi->biBelowPosition.lpPage	!=
446 	  headerBi->biTopPosition.lpPage	)
447 	{
448 	LLDEB(headerBi->biBelowPosition.lpPage,headerBi->biTopPosition.lpPage);
449 	return;
450 	}
451 
452     if  ( atTopOfRow )
453 	{
454 	rowNode->biRowAboveHeaderPosition= *lp;
455 	rowNode->biRowPrecededByHeader= 1;
456 	}
457 
458     headerHeight= headerBi->biBelowPosition.lpPageYTwips-
459 					headerBi->biTopPosition.lpPageYTwips;
460 
461     lp->lpAtTopOfColumn= 0;
462     lp->lpPageYTwips += headerHeight;
463 
464     return;
465     }
466 
467 /************************************************************************/
468 /*									*/
469 /*  Continue a table row on the next page.				*/
470 /*									*/
471 /*  1)  Finish the footnotes that we found on the current page.		*/
472 /*  2)  Move to the next page. (Column in multi column sections)	*/
473 /*  3)  Skipping to a subsequent page.. Allocate space for the table	*/
474 /*	header.								*/
475 /*  4)  Reserve space for the top border of the cells.			*/
476 /*  5)  Initialize the layout of the different table columns.		*/
477 /*									*/
478 /************************************************************************/
479 
docRowLayoutToNextColumn(BufferItem * rowNode,LayoutPosition * lpHere,const LayoutJob * lj,int atTopOfRow,BlockFrame * bf)480 static int docRowLayoutToNextColumn(
481 				BufferItem *		rowNode,
482 				LayoutPosition *	lpHere,
483 				const LayoutJob *	lj,
484 				int			atTopOfRow,
485 				BlockFrame *		bf )
486     {
487     const LayoutContext *	lc= &(lj->ljContext);
488 
489     int				inset= 0;
490     const int			belowText= 0;
491     const int			atRowTop= 0;
492     LayoutPosition		lpBelowNotes;
493 
494     /*  1  */
495     if  ( BF_HAS_FOOTNOTES( bf )				&&
496 	  ( rowNode->biTreeType == DOCinBODY		||
497 	    rowNode->biTreeType == DOCinENDNOTE	)		&&
498 	  docLayoutFootnotesForColumn( &lpBelowNotes, lpHere, bf,
499 							belowText, lj )	)
500 	{ LDEB(1); return -1;	}
501 
502     /*  2  */
503     docLayoutToNextColumn( lpHere, bf, rowNode, lj );
504 
505     /*  3  */
506     if  ( ! rowNode->biRowIsTableHeader		&&
507 	  rowNode->biRowTableHeaderRow >= 0	)
508 	{ docLayoutRowSkipHeaderHeight( lpHere, rowNode, atTopOfRow ); }
509 
510     /*  4  */
511     docLayoutCalculateRowTopInset( &inset, lc->lcDocument, rowNode, atRowTop );
512     lpHere->lpPageYTwips += inset;
513 
514     return 0;
515     }
516 
docRowToNextColumn(LayoutPosition * lpHere,BufferItem * rowNode,const LayoutJob * lj,int atTopOfRow,BlockFrame * bf,ParagraphLayoutJob * rowPlj)517 static int docRowToNextColumn(	LayoutPosition *	lpHere,
518 				BufferItem *		rowNode,
519 				const LayoutJob *	lj,
520 				int			atTopOfRow,
521 				BlockFrame *		bf,
522 				ParagraphLayoutJob *	rowPlj )
523     {
524     CellProperties *		cp;
525     int				col;
526 
527     ParagraphLayoutJob *	plj;
528 
529     LayoutPosition		lpBefore;
530 
531     lpBefore= *lpHere;
532 
533     if  ( docRowLayoutToNextColumn( rowNode, lpHere, lj, atTopOfRow, bf ) )
534 	{ LDEB(atTopOfRow); return -1;	}
535 
536     /*  5  */
537     cp= rowNode->biRowCells;
538     plj= rowPlj->pljPos.pspChildren;
539     for ( col= 0; col < rowNode->biChildCount; cp++, plj++, col++ )
540 	{
541 	const BufferItem *	cellNode= rowNode->biChildren[col];
542 	int			advanced;
543 	int			advanceAnyway= 0;
544 
545 	if  ( docLayoutStripDone( &(plj->pljPos), plj ) )
546 	    { continue;	}
547 
548 	if  ( cellNode->biChildren[plj->pljPos0.pspChild]->biLevel ==
549 								DOClevROW )
550 	    { continue;	}
551 
552 	docCommitStripLayout( &advanced, advanceAnyway, plj,
553 				lpBefore.lpPage, lpBefore.lpColumn, cellNode );
554 	}
555 
556     return 0;
557     }
558 
559 /************************************************************************/
560 /* 									*/
561 /*  Calculate the layout of a nested table row.				*/
562 /* 									*/
563 /*  1)  If the row does not fit in the current page frame, the		*/
564 /*	the situation is hopeless: Proceed on this page: The row will	*/
565 /*	be split.							*/
566 /* 									*/
567 /************************************************************************/
568 
docLayoutRowInStrip(int * pStopCode,ParagraphLayoutPosition * rowPlp,BlockFrame * bf,const LayoutJob * lj,int cellTopInset,BufferItem * rowNode)569 int docLayoutRowInStrip(	int *				pStopCode,
570 				ParagraphLayoutPosition *	rowPlp,
571 				BlockFrame *			bf,
572 				const LayoutJob *		lj,
573 				int				cellTopInset,
574 				BufferItem *			rowNode )
575     {
576     const LayoutContext *	lc= &(lj->ljContext);
577     int				stopCode= FORMATstopREADY;
578     int				toNextColumn= 0;
579     int				someAtHead= 0;
580 
581     if  ( ! rowPlp->pspChildAdvanced )
582 	{
583 	rowNode->biTopPosition= rowPlp->plpPos;
584 
585 	if  ( docLayoutStartRow( &toNextColumn, rowNode,
586 			    lc->lcDocument, &(rowPlp->plpPos), bf, rowPlp ) )
587 	    { LDEB(rowNode->biChildCount); return -1;	}
588 
589 	/*  1  */
590 	if  ( toNextColumn )
591 	    { /*LDEB(toNextColumn);*/ toNextColumn= 0;	}
592 	}
593 
594     toNextColumn= 0;
595     if  ( docLayoutRowPageStrip( &(rowPlp->plpPos),
596 					    &toNextColumn, &someAtHead,
597 					    rowNode, rowPlp, bf, lj ) )
598 	{ LDEB(1); return -1;	}
599 
600     if  ( toNextColumn )
601 	{
602 	stopCode= FORMATstopBLOCK_FULL;
603 	*pStopCode= FORMATstopBLOCK_FULL;
604 	return stopCode;
605 	}
606     else{
607 	docStripLayoutNextChild( rowPlp );
608 	stopCode= FORMATstopREADY;
609 	*pStopCode= FORMATstopREADY;
610 
611 	docLayoutFinishNodeLayout( (int *)0, rowNode, lj, &(rowPlp->plpPos) );
612 
613 	return stopCode;
614 	}
615     }
616 
617 /************************************************************************/
618 /*									*/
619 /*  Calculate the layout of a table row.				*/
620 /*									*/
621 /*  NOTE  Table headers that appear by themselves as the last table row	*/
622 /*	on the page should have been pushed to the next page. Some	*/
623 /*	thought reveals however that the result on the formatting of	*/
624 /*	the rest of the document is not altered by moving the header	*/
625 /*	row to the next page. For that reason, and to keep the 		*/
626 /*	formatter simple, we simply ignore the situation. To		*/
627 /*	compensate, the drawing code simply skips the row in its home	*/
628 /*	position and the visible result is the same.			*/
629 /*									*/
630 /*  1)  Sanity check against crashes.					*/
631 /*	This fix is a thourough memory leak. It is hardly ever		*/
632 /*	activated and it prevents crashes with incorrect rtf files.	*/
633 /*  2)  Allocate memory to monitor the progress of the layout of the	*/
634 /*	cells in the row.						*/
635 /*  3)  Initialize and place as much row content on the current page	*/
636 /*	as possible.							*/
637 /*  3a) As an optimization: It does not make sense to start a row that	*/
638 /*	has a minimum height on a page where it does not fit.		*/
639 /*	The test is not sufficient: Footnotes in the row can use the	*/
640 /*	space in such a way that on our way, we will discover that we	*/
641 /*	have no space left.						*/
642 /*  4)  Some of the content of the row did not fit on the current page.	*/
643 /*	Find out whether the row must be restarted on the next page.	*/
644 /*	(This does not make sense if the top of the row already is at	*/
645 /*	the top of the page.)						*/
646 /*  5)  When there are cells that remain empty on this page.. restart	*/
647 /*	on the next page.						*/
648 /*  6)  Go to the next page.						*/
649 /*  7)  If there is a reason, reinitialize the row layout job, to move	*/
650 /*	the whole row to the next page.					*/
651 /*  8)  Continue or restart (7) on the next page.			*/
652 /*  9)  As long as necessary, move to the next page and place content	*/
653 /*	there. (The exceptions above only apply for the first page, as	*/
654 /*	it is clearly impossible to keep the contents of a table higher	*/
655 /*	than one page on one page)					*/
656 /*									*/
657 /*  Measurements with MS-Word reveal the following:			*/
658 /*  if  trrh <  0, then the height of the row is -trrh.			*/
659 /*  if  trrh >= 0, then the height of the row is the maximum of the	*/
660 /*	height of the contents and the value of trrh. Contrary to the	*/
661 /*	exact height case, the width of the horizontal border is	*/
662 /*	added to the height of the row.					*/
663 /*  In the situation where two rows are on top of eachother, the	*/
664 /*  fattest border between them is used with a preference for the top	*/
665 /*  border of the bottom row if they have the same witdh.		*/
666 /*									*/
667 /************************************************************************/
668 
docLayoutRowNode(int * pStopCode,LayoutPosition * lpBelow,const LayoutPosition * lpTop,BufferItem * rowNode,BlockFrame * bf,int stayInThisColumn,const LayoutJob * lj)669 int docLayoutRowNode(	int *				pStopCode,
670 			LayoutPosition *		lpBelow,
671 			const LayoutPosition *		lpTop,
672 			BufferItem *			rowNode,
673 			BlockFrame *			bf,
674 			int				stayInThisColumn,
675 			const LayoutJob *		lj )
676     {
677     const LayoutContext *	lc= &(lj->ljContext);
678     int				stopCode= FORMATstopREADY;
679     int				rval= 0;
680     int				toNextColumn;
681     int				someAtHead= 0;
682 
683     ParagraphLayoutJob		rowPlj;
684 
685     LayoutPosition		lpHere;
686 
687     {
688     const int		line= 0;
689     const int		part= 0;
690 
691     docInitParagraphLayoutJob( &rowPlj );
692     docBeginParagraphLayoutProgress( &rowPlj,
693 				    rowNode->biNumberInParent,
694 				    line, part, rowNode->biNumberInParent+ 1,
695 				    lpTop );
696     }
697 
698     lpHere= *lpTop;
699 
700     /*  1  */
701     if  ( ! docIsRowNode( rowNode ) )
702 	{ LLDEB(rowNode->biNumberInParent,rowNode->biRowCellCount); return -1; }
703 
704     if  ( rowNode->biRowCellCount < rowNode->biChildCount )
705 	{
706 	LLDEB(rowNode->biRowCellCount,rowNode->biChildCount);
707 	docListNode( 0, rowNode, 0 );
708 	rowNode->biChildCount= rowNode->biRowCellCount;
709 	}
710 
711     /*  2,3  */
712     toNextColumn= 0;
713 
714     /*  3a  */
715     if  ( docLayoutStartRow( &toNextColumn, rowNode,
716 			    lc->lcDocument, &lpHere, bf, &(rowPlj.pljPos) ) )
717 	{ LDEB(rowNode->biChildCount); rval= -1; goto ready;	}
718 
719     if  ( toNextColumn )
720 	{
721 	if  ( stayInThisColumn )
722 	    { stopCode= FORMATstopFRAME_FULL; goto ready; }
723 	}
724     else{
725 	if  ( docLayoutRowPageStrip( &lpHere, &toNextColumn, &someAtHead,
726 					rowNode, &(rowPlj.pljPos), bf, lj ) )
727 	    { LDEB(1); rval= -1; goto ready;	}
728 	}
729 
730     /*  4  */
731     if  ( toNextColumn					&&
732 	  ! rowNode->biTopPosition.lpAtTopOfColumn	)
733 	{
734 	int				restartRow;
735 
736 	if  ( stayInThisColumn )
737 	    { stopCode= FORMATstopFRAME_FULL; goto ready; }
738 
739 	/*  5, 7  */
740 	restartRow= BI_ROW_IS_ONE_PAGE( rowNode ) ||
741 				    ! rowPlj.pljPos.pspChildAdvanced ||
742 				    someAtHead;
743 	/*  6  */
744 	if  ( docRowToNextColumn( &lpHere, rowNode, lj,
745 						restartRow, bf, &rowPlj ) )
746 	    { LDEB(toNextColumn); rval= -1; goto ready;	}
747 
748 	/*  7  */
749 	if  ( restartRow )
750 	    {
751 	    rowNode->biTopPosition= lpHere;
752 
753 	    if  ( rowNode->biRowIsTableHeader		||
754 		  rowNode->biRowTableHeaderRow < 0	)
755 		{ rowNode->biRowAboveHeaderPosition= rowNode->biTopPosition; }
756 
757 	    if  ( docLayoutStartRowCells( rowNode, lc->lcDocument,
758 					    &lpHere, bf, &(rowPlj.pljPos) ) )
759 		{ LDEB(rowNode->biChildCount); rval= -1; goto ready;	}
760 	    toNextColumn= 0; /* irrelevant here */
761 	    }
762 
763 	/*  8  */
764 	if  ( docLayoutRowPageStrip( &lpHere, &toNextColumn, &someAtHead,
765 					rowNode, &(rowPlj.pljPos), bf, lj ) )
766 	    { LDEB(1); rval= -1; goto ready;	}
767 	}
768 
769     /*  9  */
770     while( toNextColumn )
771 	{
772 	const int	atTopOfRow= 0;
773 
774 	if  ( stayInThisColumn )
775 	    { stopCode= FORMATstopFRAME_FULL; goto ready; }
776 
777 	if  ( docRowToNextColumn( &lpHere, rowNode, lj,
778 						atTopOfRow, bf, &rowPlj ) )
779 	    { LDEB(toNextColumn); rval= -1; goto ready;	}
780 
781 	if  ( docLayoutRowPageStrip( &lpHere, &toNextColumn, &someAtHead,
782 					rowNode, &(rowPlj.pljPos), bf, lj ) )
783 	    { LDEB(1); rval= -1; goto ready;	}
784 	}
785 
786   ready:
787 
788     docCleanParagraphLayoutJob( &rowPlj );
789 
790     if  ( ! rval )
791 	{
792 	*pStopCode= stopCode;
793 	*lpBelow= lpHere;
794 	}
795 
796     return rval;
797     }
798 
799