1 /************************************************************************/
2 /*									*/
3 /*  Layout of a document. Layout of a series of paragraphs in a common	*/
4 /*  parent.								*/
5 /*									*/
6 /************************************************************************/
7 
8 #   include	"docLayoutConfig.h"
9 
10 #   include	<stddef.h>
11 
12 #   include	"docLayout.h"
13 #   include	<docPageGrid.h>
14 #   include	<docTreeType.h>
15 #   include	<docTreeNode.h>
16 #   include	<docNodeTree.h>
17 #   include	<docTextLine.h>
18 
19 #   include	<appDebugon.h>
20 
21 /************************************************************************/
22 /*									*/
23 /*  Preparation for vertical alignment of tabe cells. It is also used	*/
24 /*  to position the contents of a frame.				*/
25 /*									*/
26 /************************************************************************/
27 
docRedoParaStripLayout(const LayoutJob * lj,BlockFrame * bf,const LayoutPosition * lpFrom,BufferItem * cellNode,int childFrom,int childUpto)28 void docRedoParaStripLayout(	const LayoutJob *		lj,
29 				BlockFrame *			bf,
30 				const LayoutPosition *		lpFrom,
31 				BufferItem *			cellNode,
32 				int				childFrom,
33 				int				childUpto )
34     {
35     const LayoutContext *	lc= &(lj->ljContext);
36     int				stopCode= FORMATstopREADY;
37     int				para;
38     BufferItem *		paraBi0= cellNode->biChildren[childFrom];
39 
40     int				xStopCode= 0;
41 
42     ParagraphLayoutPosition	plpRedo;
43     const int			isRedo= 1;
44 
45     docInitParagraphLayoutPosition( &plpRedo );
46 
47     docStripLayoutStartChild( &plpRedo, childFrom );
48     plpRedo.plpPos= *lpFrom;
49 
50     /*  1  */
51     if  ( docLayoutStartParagraph( lj, &xStopCode, paraBi0, bf, &plpRedo ) )
52 	{ LDEB(1); return;	}
53 
54     if  ( xStopCode != FORMATstopREADY )
55 	{ LDEB(xStopCode); return;	}
56 
57     for ( para= childFrom; para < childUpto; para++ )
58 	{
59 	int		changed= 0;
60 	int		accepted;
61 	BufferItem *	paraNode= cellNode->biChildren[para];
62 
63 	docStripLayoutStartChild( &plpRedo, para );
64 
65 	paraNode->biTopPosition= plpRedo.plpPos;
66 
67 	accepted= docLayoutParaLines( &stopCode, isRedo,
68 					&(plpRedo.plpParagraphFrame),
69 					&(plpRedo.plpPos), &(plpRedo.pspLine),
70 					bf, lj, paraNode, plpRedo.pspPart );
71 	if  ( accepted < 0 )
72 	    { LDEB(accepted); break;	}
73 
74 	docLayoutSetNodeBottom( &changed, paraNode, &(plpRedo.plpPos),
75 					    lc, lj->ljChangedRectanglePixels );
76 	}
77 
78     return;
79     }
80 
81 /************************************************************************/
82 
docLayoutChildInStrip(int * pStopCode,ParagraphLayoutPosition * plp,BlockFrame * bf,const LayoutJob * lj,int cellTopInset,BufferItem * childNode)83 static int docLayoutChildInStrip(
84 			int *				pStopCode,
85 			ParagraphLayoutPosition *	plp,
86 			BlockFrame *			bf,
87 			const LayoutJob *		lj,
88 			int				cellTopInset,
89 			BufferItem *			childNode )
90     {
91     switch( childNode->biLevel )
92 	{
93 	case DOClevPARA:
94 	    return docLayoutParagraphInStrip( pStopCode, plp, bf, lj,
95 						    cellTopInset, childNode );
96 	case DOClevROW:
97 	    return docLayoutRowInStrip( pStopCode, plp, bf, lj,
98 						    cellTopInset, childNode );
99 	default:
100 	    LDEB(childNode->biLevel); return -1;
101 	}
102     }
103 
104 /************************************************************************/
105 
docLayoutGetChildFrame(int * pFrameNumber,FrameProperties * fp,const BufferDocument * bd,const BufferItem * childNode)106 static int docLayoutGetChildFrame(	int *			pFrameNumber,
107 					FrameProperties *	fp,
108 					const BufferDocument *	bd,
109 					const BufferItem *	childNode )
110     {
111     int		isFrame= 0;
112     int		frameNumber;
113 
114     switch( childNode->biLevel )
115 	{
116 	case DOClevPARA:
117 	    frameNumber= childNode->biParaFrameNumber;
118 	    break;
119 	case DOClevROW:
120 	    frameNumber= childNode->biRowFrameNumber;
121 	    break;
122 	default:
123 	    LDEB(childNode->biLevel);
124 	    frameNumber= -1;
125 	    break;
126 	}
127 
128     if  ( frameNumber >= 0 )
129 	{
130 	docGetFramePropertiesByNumber( fp, bd, frameNumber );
131 	isFrame= DOCisFRAME( fp );
132 	}
133 
134     *pFrameNumber= frameNumber;
135     return isFrame;
136     }
137 
138 /************************************************************************/
139 /*									*/
140 /*  Layout as much of a series of paragraph as fits on the current	*/
141 /*  page. (Actually the column on the page).				*/
142 /*									*/
143 /*  a)  Do not format children that belong to different frames.		*/
144 /*									*/
145 /************************************************************************/
146 
docLayoutStripChildren(int * pStopCode,ParagraphLayoutJob * plj,BlockFrame * bfFlow,const LayoutJob * lj,BufferItem * cellNode)147 int docLayoutStripChildren(	int *				pStopCode,
148 				ParagraphLayoutJob *		plj,
149 				BlockFrame *			bfFlow,
150 				const LayoutJob *		lj,
151 				BufferItem *			cellNode )
152     {
153     const LayoutContext *	lc= &(lj->ljContext);
154     ParagraphLayoutPosition *	plp= &(plj->pljPos);
155     const int			childFrom= plp->pspChild;
156     BufferItem *		childNode= cellNode->biChildren[childFrom];
157 
158     BlockFrame *		bf= bfFlow;
159 
160     const BufferDocument *	bd= lc->lcDocument;
161 
162     FrameProperties		fpBegin;
163     int				frameBegin;
164     int				wasFrame;
165 
166     FrameProperties		fpRow;
167     int				frameRow= -1;
168     int				rowIsFrame= 0;
169 
170     BufferItem *		rowBi;
171 
172     if  ( ! docIsCellNode( cellNode ) )
173 	{ SDEB(docLevelStr(cellNode->biLevel)); return -1;	}
174     if  ( childFrom >= cellNode->biChildCount )
175 	{ LLDEB(childFrom,cellNode->biChildCount); return -1;	}
176 
177     rowBi= docGetRowNode( cellNode );
178     if  ( rowBi )
179 	{
180 	DocumentPosition	dp;
181 
182 	if  ( ! docHeadPosition( &dp, rowBi ) )
183 	    {
184 	    rowIsFrame= docLayoutGetChildFrame( &frameRow, &fpRow,
185 							    bd, dp.dpNode );
186 	    }
187 	}
188 
189     /*  a  */
190     childNode= cellNode->biChildren[plj->pljPos.pspChild];
191     wasFrame= docLayoutGetChildFrame( &frameBegin, &fpBegin, bd, childNode );
192     if  ( wasFrame && ( ! rowIsFrame || frameRow != frameBegin ) )
193 	{
194 	BlockFrame			bfTextFrame;
195 	ParagraphLayoutPosition		plpTextFrame;
196 	int				frameHeight= fpBegin.fpHighTwips;
197 
198 	if  ( frameHeight < 0 )
199 	    { frameHeight= -frameHeight;	}
200 
201 	plpTextFrame= *plp;
202 	plp= &plpTextFrame;
203 
204 	docLayoutInitBlockFrame( &bfTextFrame );
205 	docLayoutSetTextFrame( &bfTextFrame, &(plp->plpPos),
206 						bf, &fpBegin, frameHeight );
207 
208 	plp->plpPos.lpPageYTwips= bfTextFrame.bfContentRect.drY0;
209 	bf= &bfTextFrame;
210 	}
211 
212     while( plp->pspChild < plj->pljChildUpto )
213 	{
214 	int			stopCode= FORMATstopREADY;
215 	int			ret;
216 
217 	FrameProperties		fpHere;
218 	int			frameHere;
219 	int			isFrame;
220 
221 	childNode= cellNode->biChildren[plp->pspChild];
222 	isFrame= docLayoutGetChildFrame( &frameHere, &fpHere, bd, childNode );
223 
224 	/*  a  */
225 	if  ( isFrame != wasFrame				||
226 	      ( wasFrame && ( frameHere != frameBegin )	)	)
227 	    {
228 	    if  ( wasFrame )
229 		{
230 		docLayoutFinishFrame( &fpBegin, bf, bfFlow, lj,
231 			&(plj->pljPos), cellNode, childFrom, plp->pspChild );
232 
233 		plj->pljPos= *plp;
234 		}
235 
236 	    *pStopCode= FORMATstopNEXT_FRAME;
237 	    break;
238 	    }
239 
240 	ret= docLayoutChildInStrip( &stopCode, plp, bf, lj,
241 					cellNode->biCellTopInset, childNode );
242 	if  ( ret < 0 )
243 	    { LDEB(ret); return -1;		}
244 
245 	switch( ret )
246 	    {
247 	    case FORMATstopBLOCK_FULL:
248 	    case FORMATstopPAGE_BREAK:
249 	    case FORMATstopCOLUMN_BREAK:
250 		*pStopCode= stopCode;
251 		break;
252 
253 	    case FORMATstopPARTIAL:
254 	    case FORMATstopREADY:
255 		continue;
256 
257 	    default:
258 		LDEB(ret); continue;
259 	    }
260 
261 	break;
262 	}
263 
264     if  ( docLayoutStripDone( plp, plj ) )
265 	{ *pStopCode= FORMATstopREADY;	}
266 
267     return 0;
268     }
269 
270 /************************************************************************/
271 /*									*/
272 /*  Find a start point for the formatter to layout lines. A certain	*/
273 /*  work ahead is necessary to decide whether work on line layout can	*/
274 /*  be used or not. docCommitStripLayout() is used to decide what	*/
275 /*  work is final and what possibly is to be redone.			*/
276 /*									*/
277 /*  docCommitStripLayout() is called when a column is full. In	*/
278 /*  this case, everything that is not final yet needs to be moved to	*/
279 /*  the next page.							*/
280 /*									*/
281 /*  -   Insure that the constraints comming from Widow/Orphan control	*/
282 /*	are been obeyed.						*/
283 /*  -   Insure that paragraphs that should not be divided over pages	*/
284 /*	are not split.							*/
285 /*  -   Insure that paragraphs that should be with the next one as a	*/
286 /*	header really are with it. (Experimenting with Word shows that	*/
287 /*	paragraphs that should be with the next one should be		*/
288 /*	completely with it.)						*/
289 /*									*/
290 /*  When any of the above is violated, find a solution that respects	*/
291 /*  the requirements by pushing offending paragraphs or lines down.	*/
292 /*									*/
293 /*  docCommitStripLayout() shifts 'plp0' to the last position that is	*/
294 /*  not below 'plp1' that is not influenced by the layout of position	*/
295 /*  on 'plp1' or below. Everything before 'plp1' is formatted and	*/
296 /*  plp1->plpPos is the position where formatting would continue if	*/
297 /*  docCommitStripLayout() moved 'plp0' onto 'plp1'. (As it often does)	*/
298 /*									*/
299 /*  REGULAR APPROACH							*/
300 /*  ================							*/
301 /*  a)  Avoid superfluous work and the handling of this exception	*/
302 /*	below: Commit an explit page break.				*/
303 /*  b)	If the current position is a legal position for a page break..	*/
304 /*	break here.							*/
305 /*									*/
306 /*  'Keep With Next' and 'Widow/Orphan Contol'				*/
307 /*  ==========================================				*/
308 /*  1)  Find the place to begin. Anything on a previous page is final:	*/
309 /*	It will not be shifted to the next page. (Paragraph)		*/
310 /*  2)	Idem: Line. The line found here might very well be irrelevant	*/
311 /*	because a different paragraph to commit is found below.		*/
312 /*  3)	Commit all paragraphs before the current one that do not have	*/
313 /*	the 'Keep with Next' flag.					*/
314 /*	flag.								*/
315 /*  4)	If the paragraph to be committed is before the current one	*/
316 /*	commit the position we have found. This can be:			*/
317 /*	-   The first line on the current page (from 2)			*/
318 /*	    [ This case is however excluded by the exception code (0)].	*/
319 /*	-   The head of a series of KeepWithNext paragraphs. (from 3)	*/
320 /*  5)	When this paragraph is to be kept together, restart from its	*/
321 /*	beginning.							*/
322 /*  6)	When Widow/Orphan control is active.. Do not commit the first	*/
323 /*	line before the whole paragraph is committed.			*/
324 /*  7)	The special cases of the last line of a paragraph with widow	*/
325 /*	orphan control and a paragraph with three lines are covered	*/
326 /*	in docLayoutStripChildren() at the end of a paragraph.		*/
327 /*	So no exceptions have to be made here. Also note the		*/
328 /*	preparations in docAdjustParaLayout().				*/
329 /*									*/
330 /*  8)	And finally when no exception applies, start from where we are	*/
331 /*	now.								*/
332 /*									*/
333 /************************************************************************/
334 
docCommitStripLayout_x(ParagraphLayoutPosition * plp0,const ParagraphLayoutPosition * plp1,int advanceAnyway,int page,int column,const BufferItem * cellNode)335 static void docCommitStripLayout_x(
336 				ParagraphLayoutPosition *	plp0,
337 				const ParagraphLayoutPosition *	plp1,
338 				int				advanceAnyway,
339 				int				page,
340 				int				column,
341 				const BufferItem *		cellNode )
342     {
343     const BufferItem *		paraBi0;
344     const BufferItem *		paraBi1;
345     const TextLine *		tl;
346 
347     int				para;
348 
349     int				line0;
350 
351     paraBi0= cellNode->biChildren[plp0->pspChild];
352     paraBi1= (const BufferItem *)0;
353 
354     if  ( paraBi0->biLevel != DOClevPARA )
355 	{ LSDEB(paraBi0->biLevel,docLevelStr(paraBi0->biLevel)); return; }
356 
357     /*  a  */
358     if  ( plp1->pspChild < cellNode->biChildCount )
359 	{
360 	int		line1;
361 
362 	paraBi1= cellNode->biChildren[plp1->pspChild];
363 
364 	line1= plp1->pspLine;
365 
366 	if  ( line1- 1 >= 0				&&
367 	      line1- 1 < paraBi1->biParaLineCount	)
368 	    {
369 	    const TextLine *	tl= paraBi1->biParaLines+ line1- 1;
370 
371 	    if  ( tl->tlFlags & TLflagBLOCKBREAK )
372 		{
373 		*plp0= *plp1;
374 		return;
375 		}
376 	    }
377 	}
378 
379     /*  b  */
380     if  ( paraBi1			&&
381 	  paraBi1->biParaKeepOnPage	&&
382 	  ! paraBi1->biParaKeepWithNext	&&
383 	  plp1->pspLine > 0		)
384 	{
385 	int		line= 1;
386 
387 	if  ( paraBi1->biParaWidowControl )
388 	    { line++;	}
389 
390 	if  ( plp1->pspLine >= line )
391 	    {
392 	    *plp0= *plp1;
393 	    return;
394 	    }
395 	}
396 
397     /*  1  */
398     while( plp0->pspChild < plp1->pspChild )
399 	{
400 	if  ( paraBi0->biBelowPosition.lpPage >  page )
401 	    { break;	}
402 	if  ( paraBi0->biBelowPosition.lpPage == page		&&
403 	      paraBi0->biBelowPosition.lpColumn >= column	)
404 	    { break;	}
405 
406 	docStripLayoutNextChild( plp0 );
407 	paraBi0= cellNode->biChildren[plp0->pspChild];
408 	}
409 
410     /*  2  */
411     if  ( plp0->pspChild < plp1->pspChild )
412 	{ line0= paraBi0->biParaLineCount;	}
413     else{ line0= plp1->pspLine;			}
414 
415     tl= paraBi0->biParaLines+ plp0->pspLine;
416     while( plp0->pspLine < line0 && plp0->pspLine < paraBi0->biParaLineCount )
417 	{
418 	if  ( tl->tlTopPosition.lpPage >  page )
419 	    { break;	}
420 	if  ( tl->tlTopPosition.lpPage == page	&&
421 	      tl->tlTopPosition.lpColumn >= column	)
422 	    { break;	}
423 
424 	plp0->pspLine++; tl++;
425 	}
426 
427     /*  3  */
428     for ( para= plp0->pspChild; para < plp1->pspChild; para++ )
429 	{
430 	const BufferItem *	paraNode= cellNode->biChildren[para];
431 
432 	if  ( advanceAnyway || ! paraNode->biParaKeepWithNext )
433 	    {
434 	    docStripLayoutStartChild( plp0, para+ 1 );
435 
436 	    if  ( plp0->pspChild < cellNode->biChildCount )
437 		{ paraBi0= cellNode->biChildren[plp0->pspChild];	}
438 	    /*  else .. return below */
439 	    }
440 	}
441 
442     /*  4  */
443     if  ( plp0->pspChild < plp1->pspChild )
444 	{ return;	}
445 
446     if  ( plp0->pspChild != plp1->pspChild )
447 	{ LLLLDEB(page,column,plp0->pspChild,plp1->pspChild );	}
448 
449     if  ( plp0->pspChild >= cellNode->biChildCount )
450 	{ return;	}
451 
452     /*  5  */
453     if  ( ! advanceAnyway			&&
454 	  ( paraBi0->biParaKeepOnPage	||
455 	    paraBi0->biParaKeepWithNext	)	)
456 	{
457 	docStripLayoutStartChild( plp0, plp0->pspChild );
458 	return;
459 	}
460 
461     /*  6  */
462     if  ( ! advanceAnyway		&&
463 	  paraBi1			&&
464 	  paraBi1->biParaWidowControl	&&
465 	  plp1->pspLine == 1		&&
466 	  paraBi1->biParaLineCount >= 1	)
467 	{
468 	tl= paraBi1->biParaLines+ 0;
469 
470 	if  ( tl->tlFirstParticule+ tl->tlParticuleCount <
471 					paraBi1->biParaParticuleCount	)
472 	    {
473 	    docStripLayoutStartChild( plp0, plp0->pspChild );
474 	    return;
475 	    }
476 	}
477 
478     /*  7  */
479 
480     /*  8  */
481     *plp0= *plp1;
482 
483     return;
484     }
485 
486 /************************************************************************/
487 /*									*/
488 /*  Find out whether the fact that layout has proceeded to plj->pljPos	*/
489 /*  makes any layout final. If so.. Move pljPos0 past what has become	*/
490 /*  final.								*/
491 /*									*/
492 /************************************************************************/
493 
494 # define docSetLayoutProgress( plpt, plpf ) \
495     { \
496     (plpt)->pspChild= (plpf)->pspChild; \
497     (plpt)->pspChildAdvanced= (plpf)->pspChildAdvanced; \
498     (plpt)->pspPart= (plpf)->pspPart; \
499     (plpt)->pspLine= (plpf)->pspLine; \
500     }
501 
docCompareLayoutProgress(const ParagraphLayoutPosition * plp0,const ParagraphLayoutPosition * plp1)502 static int docCompareLayoutProgress(
503 			const ParagraphLayoutPosition *	plp0,
504 			const ParagraphLayoutPosition *	plp1 )
505     {
506     if  ( plp1->pspChild > plp0->pspChild )
507 	{ return  1;	}
508     if  ( plp1->pspChild < plp0->pspChild )
509 	{ return -1;	}
510 
511     if  ( plp1->pspPart > plp0->pspPart )
512 	{ return  1;	}
513     if  ( plp1->pspPart < plp0->pspPart )
514 	{ return -1;	}
515 
516     return 0;
517     }
518 
docCommitStripLayout(int * pAdvanced,int advanceAnyway,ParagraphLayoutJob * plj,int page,int column,const BufferItem * cellNode)519 void docCommitStripLayout(
520 				int *				pAdvanced,
521 				int				advanceAnyway,
522 				ParagraphLayoutJob *		plj,
523 				int				page,
524 				int				column,
525 				const BufferItem *		cellNode )
526     {
527     int				advanced= 0;
528     ParagraphLayoutPosition	plp0;
529 
530     plp0= plj->pljPos0;
531 
532     docCommitStripLayout_x( &plp0, &(plj->pljPos),
533 				    advanceAnyway, page, column, cellNode );
534 
535     advanced= ( docCompareLayoutProgress( &plp0, &(plj->pljPos0) ) < 0 );
536     if  ( advanced )
537 	{
538 	docSetLayoutProgress( &(plj->pljPos0), &plp0 );
539 	docSetLayoutProgress( &(plj->pljPos), &plp0 );
540 	}
541     else{
542 #	if 0
543 	int cmp= docCompareLayoutProgress( &(plj->pljPos0), &(plj->pljPos) );
544 	if  ( cmp >= 0 )
545 	    { LDEB(cmp);	}
546 #	endif
547 	/* Prevent loops: Be sure to advance */
548 	docSetLayoutProgress( &(plj->pljPos0), &(plj->pljPos) );
549 	}
550 
551     *pAdvanced= advanced;
552     }
553 
554 /************************************************************************/
555 /*									*/
556 /*  Find out where to start formatting a strip.				*/
557 /*  After some thought: That is the position that would be committed	*/
558 /*  if the strip were formatted upto the stat position.			*/
559 /*									*/
560 /************************************************************************/
561 
docFindStripLayoutOrigin(ParagraphLayoutJob * plj,int page,int column,const BufferItem * cellNode)562 void docFindStripLayoutOrigin(	ParagraphLayoutJob *		plj,
563 				int				page,
564 				int				column,
565 				const BufferItem *		cellNode )
566     {
567     int				advanceAnyway= 0;
568 
569     docCommitStripLayout_x( &(plj->pljPos0), &(plj->pljPos),
570 					advanceAnyway, page, column, cellNode );
571 
572     return;
573     }
574 
575 /************************************************************************/
576 /*									*/
577 /*  Format the lines in a series of paragraphs. On the way keep an	*/
578 /*  administration on where to restart formatting at a page break.	*/
579 /*									*/
580 /*  1)  Place as much as fits on the first page.			*/
581 /*  2)  While unformatted paragraphs remain: place some more on		*/
582 /*	subsequent pages.						*/
583 /*  3)  First place the footnotes on the page.				*/
584 /*  4)  Then find out where to restart the layout job on the next page	*/
585 /*	Widow/Orphan control etc can cause some of the text that we	*/
586 /*	already formatted to go to the next page.			*/
587 /*  5)  Skip to the next page.						*/
588 /*  6)  Determine available space on the next page.			*/
589 /*  7)  Place as much as fits on the next page.				*/
590 /*									*/
591 /************************************************************************/
592 
docLayoutStackedStrip(BufferItem * cellNode,BlockFrame * bf,const LayoutJob * lj,ParagraphLayoutJob * plj)593 int docLayoutStackedStrip(	BufferItem *			cellNode,
594 				BlockFrame *			bf,
595 				const LayoutJob *		lj,
596 				ParagraphLayoutJob *		plj )
597     {
598     LayoutPosition		lpBefore;
599 
600     int				prevAdvanced= 1;
601     int				advanceAnyway= 0;
602     int				stopCode= FORMATstopREADY;
603     int				prevStopCode= FORMATstopREADY;
604 
605     lpBefore= plj->pljPos.plpPos;
606 
607     /*  1  */
608     if  ( docLayoutStripChildren( &stopCode, plj, bf, lj, cellNode ) )
609 	{ LDEB(1); return -1;	}
610 
611     /*  2  */
612     while( stopCode != FORMATstopREADY		&&
613 	   stopCode != FORMATstopFRAME_FULL	)
614 	{
615 	int				advanced;
616 	const int			belowText= 0;
617 	LayoutPosition			lpBelowNotes;
618 
619 	/*  3  */
620 	if  ( BF_HAS_FOOTNOTES( bf )					&&
621 	      ( cellNode->biTreeType == DOCinBODY		||
622 	        cellNode->biTreeType == DOCinENDNOTE	)	&&
623 	      ! bf->bfFootnotesPlaced					&&
624 	      docLayoutFootnotesForColumn( &lpBelowNotes,
625 			    &(plj->pljPos.plpPos), bf, belowText, lj )	)
626 	    { LDEB(1); return -1;	}
627 
628 	/*  4  */
629 	docCommitStripLayout( &advanced, advanceAnyway, plj,
630 					lpBefore.lpPage, lpBefore.lpColumn,
631 					cellNode );
632 
633 	/*  5  */
634 	switch( stopCode )
635 	    {
636 	    case FORMATstopBLOCK_FULL:
637 	    case FORMATstopCOLUMN_BREAK:
638 		docLayoutToNextColumn( &(plj->pljPos.plpPos), bf, cellNode, lj );
639 		break;
640 
641 	    case FORMATstopPAGE_BREAK:
642 		docLayoutToNextColumn( &(plj->pljPos.plpPos), bf, cellNode, lj );
643 		while( plj->pljPos.plpPos.lpColumn > 0 )
644 		    {
645 		    docLayoutToNextColumn( &(plj->pljPos.plpPos),
646 							    bf, cellNode, lj );
647 		    }
648 		break;
649 
650 	    default:
651 		break;
652 	    }
653 
654 	if  ( ! advanced )
655 	    {
656 	    if  ( ! prevAdvanced )
657 		{
658 		if  ( advanceAnyway )
659 		    {
660 		    LLLDEB(prevAdvanced,advanced,advanceAnyway);
661 		    LLDEB(prevStopCode,stopCode);
662 		    RECTDEB(&(plj->pljPos.plpParagraphFrame.pfParaContentRect));
663 
664 		    docStripLayoutNextChild( &(plj->pljPos) );
665 		    docSetLayoutProgress( &(plj->pljPos0), &(plj->pljPos) );
666 		    advanced= 1;
667 
668 		    if  ( docLayoutStripDone( &(plj->pljPos), plj ) )
669 			{ break;	}
670 		    }
671 		else{ advanceAnyway= 1;	}
672 		}
673 	    }
674 
675 	prevAdvanced= advanced;
676 
677 	/*  6  */
678 	docCellStripFrame( cellNode, bf, plj );
679 
680 	/*  7  */
681 	lpBefore= plj->pljPos.plpPos;
682 
683 	prevStopCode= stopCode;
684 	if  ( docLayoutStripChildren( &stopCode, plj, bf, lj, cellNode ) )
685 	    { LDEB(1); return -1;	}
686 	}
687 
688     if  ( cellNode->biChildCount > 0 )
689 	{ cellNode->biTopPosition= cellNode->biChildren[0]->biTopPosition; }
690 
691     return 0;
692     }
693 
694 /************************************************************************/
695 /*									*/
696 /*  Calculate the formatting frame for a paragraph layout.		*/
697 /*									*/
698 /************************************************************************/
699 
docCellStripFrame(BufferItem * cellNode,const BlockFrame * bf,ParagraphLayoutJob * plj)700 void docCellStripFrame(		BufferItem *			cellNode,
701 				const BlockFrame *		bf,
702 				ParagraphLayoutJob *		plj )
703 
704     {
705     BufferItem *		childNode;
706     ParagraphFrame *		pf= &(plj->pljPos.plpParagraphFrame);
707 
708     childNode= cellNode->biChildren[plj->pljPos.pspChild];
709 
710     if  ( childNode->biLevel == DOClevPARA )
711 	{ docParagraphFrameTwips( pf, bf, childNode );	}
712     else{ docCellFrameTwips( pf, bf, cellNode );	}
713 
714     return;
715     }
716 
717