1 /************************************************************************/
2 /*									*/
3 /*  Geometry calculations about external items.				*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docLayoutConfig.h"
8 
9 #   include	<stddef.h>
10 
11 #   include	"docLayout.h"
12 #   include	"docSelectLayout.h"
13 #   include	<docPageGrid.h>
14 #   include	<docField.h>
15 #   include	<docTreeType.h>
16 #   include	<docTreeNode.h>
17 #   include	<docTextLine.h>
18 #   include	<docNotes.h>
19 #   include	<docRecalculateFields.h>
20 
21 #   include	<appDebugon.h>
22 
23 /************************************************************************/
24 /*									*/
25 /*  Determine the box around a header or a footer.			*/
26 /*									*/
27 /************************************************************************/
28 
docNoteSeparatorBox(DocumentRectangle * dr,int noteItKind,int noteSepKind,int page,int column,const LayoutContext * lc)29 static int docNoteSeparatorBox(	DocumentRectangle *		dr,
30 				int				noteItKind,
31 				int				noteSepKind,
32 				int				page,
33 				int				column,
34 				const LayoutContext *		lc )
35     {
36     DocumentTree *		eiNoteSep;
37     int				y0Twips;
38     struct DocumentNote *	dnFirstNote;
39     DocumentField *		dfNote;
40 
41     dfNote= docGetFirstNoteInColumn( &dnFirstNote, lc->lcDocument,
42 						page, column, noteItKind );
43 
44     if  ( ! dfNote )
45 	{ XDEB(dfNote); return -1;	}
46 
47     if  ( docNoteSeparatorRectangle( dr, &eiNoteSep, &y0Twips,
48 					    dnFirstNote, noteSepKind, lc ) )
49 	{ LDEB(1); return -1;	}
50 
51     return 0;
52     }
53 
docGetBoxAroundTree(DocumentRectangle * dr,const BufferItem * bodySectNode,const DocumentTree * tree,int justUsed,int page,int column,const LayoutContext * lc)54 int docGetBoxAroundTree(	DocumentRectangle *		dr,
55 				const BufferItem *		bodySectNode,
56 				const DocumentTree *		tree,
57 				int				justUsed,
58 				int				page,
59 				int				column,
60 				const LayoutContext *		lc )
61     {
62     int				rval= 0;
63     BufferItem *		treeRoot= tree->dtRoot;
64 
65     BlockFrame			bf;
66     DocumentRectangle		drTwips;
67     DocumentRectangle		drBox;
68 
69     docLayoutInitBlockFrame( &bf );
70 
71     if  ( ! treeRoot )
72 	{ XDEB(treeRoot); rval= -1; goto ready;	}
73 
74     switch( treeRoot->biTreeType )
75 	{
76 	case DOCinFIRST_HEADER:
77 	case DOCinLEFT_HEADER:
78 	case DOCinRIGHT_HEADER:
79 	case DOCinFIRST_FOOTER:
80 	case DOCinLEFT_FOOTER:
81 	case DOCinRIGHT_FOOTER:
82 
83 	    docBlockFrameTwips( &bf, treeRoot, lc->lcDocument, page, column );
84 
85 	    drTwips= bf.bfContentRect;
86 
87 	    if  ( justUsed )
88 		{
89 		drTwips.drY0= tree->dtY0UsedTwips;
90 		drTwips.drY1= tree->dtY1UsedTwips;
91 		}
92 	    else{
93 		drTwips.drY0= tree->dtY0ReservedTwips;
94 		drTwips.drY1= tree->dtY1ReservedTwips;
95 		}
96 
97 	    docGetPixelRect( &drBox, lc, &drTwips, page );
98 
99 	    *dr= drBox; break;
100 
101 	case DOCinFOOTNOTE:
102 	case DOCinENDNOTE:
103 
104 	    {
105 	    DocumentPosition	dpTop;
106 	    DocumentPosition	dpBot;
107 
108 	    int			lineTop;
109 	    int			lineBot;
110 
111 	    int			partTop;
112 	    int			partBot;
113 
114 	    const TextLine *	tlTop;
115 	    const TextLine *	tlBot;
116 
117 	    LayoutPosition	lpTop;
118 	    LayoutPosition	lpBot;
119 
120 	    docBlockFrameTwips( &bf, tree->dtRoot, lc->lcDocument,
121 							    page, column );
122 
123 	    if  ( docGetFirstInColumnForNode( &dpTop, &lineTop, &partTop,
124 						tree->dtRoot, page, column ) )
125 		{
126 		LLDEB(page,column);
127 		SDEB(docTreeTypeStr(tree->dtRoot->biTreeType));
128 		rval= -1; goto ready;
129 		}
130 
131 	    if  ( docGetLastInColumnForNode( &dpBot, &lineBot, &partBot,
132 						tree->dtRoot, page, column ) )
133 		{ LDEB(page); rval= -1; goto ready;	}
134 
135 	    tlTop= dpTop.dpNode->biParaLines+ lineTop;
136 	    tlBot= dpBot.dpNode->biParaLines+ lineBot;
137 
138 	    lpTop= tlTop->tlTopPosition;
139 	    lpBot= tlBot->tlTopPosition;
140 	    lpBot.lpPageYTwips += tlBot->tlLineStride;
141 
142 	    docGetPixelRectForPos( &drBox, lc,
143 			     bf.bfContentRect.drX0, bf.bfContentRect.drX1,
144 			     &lpTop, &lpBot );
145 	    }
146 
147 	    *dr= drBox; break;
148 
149 	case DOCinFTNSEP:
150 	case DOCinFTNSEPC:
151 	case DOCinFTNCN:
152 
153 	    if  ( docNoteSeparatorBox( &drBox,
154 			    DOCinFOOTNOTE, treeRoot->biTreeType,
155 			    page, column, lc ) )
156 		{ LLDEB(page,column); rval= -1; goto ready;	}
157 
158 	    *dr= drBox; break;
159 
160 	case DOCinAFTNSEP:
161 	case DOCinAFTNSEPC:
162 	case DOCinAFTNCN:
163 
164 	    if  ( docNoteSeparatorBox( &drBox,
165 			    DOCinENDNOTE, treeRoot->biTreeType,
166 			    page, column, lc ) )
167 		{ LLDEB(page,column); rval= -1; goto ready;	}
168 
169 	    *dr= drBox; break;
170 
171 	default:
172 	    LDEB(treeRoot->biTreeType);
173 	    rval= -1; goto ready;
174 	}
175 
176   ready:
177 
178     docLayoutCleanBlockFrame( &bf );
179 
180     return rval;
181     }
182 
183 /************************************************************************/
184 
docPlaceHeader(DocumentTree * tree,const DocumentGeometry * dgSect)185 static void docPlaceHeader(	DocumentTree *			tree,
186 				const DocumentGeometry *	dgSect )
187     {
188     tree->dtY0UsedTwips= tree->dtRoot->biTopPosition.lpPageYTwips;
189     tree->dtY1UsedTwips= tree->dtRoot->biBelowPosition.lpPageYTwips;
190 
191     tree->dtY0ReservedTwips= dgSect->dgHeaderPositionTwips;
192     tree->dtY1ReservedTwips= dgSect->dgTopMarginTwips;
193 
194     if  ( tree->dtY1ReservedTwips < tree->dtY1UsedTwips )
195 	{ tree->dtY1ReservedTwips=  tree->dtY1UsedTwips;	}
196 
197     return;
198     }
199 
docPlaceFooter(DocumentTree * tree,const DocumentGeometry * dgSect)200 static void docPlaceFooter(	DocumentTree *			tree,
201 				const DocumentGeometry *	dgSect )
202     {
203     int	high= tree->dtRoot->biBelowPosition.lpPageYTwips-
204 			    tree->dtRoot->biTopPosition.lpPageYTwips;
205 
206     tree->dtY1UsedTwips=
207 		dgSect->dgPageHighTwips- dgSect->dgFooterPositionTwips;
208     tree->dtY0UsedTwips= tree->dtY1UsedTwips- high;
209 
210     tree->dtY0ReservedTwips=
211 		dgSect->dgPageHighTwips- dgSect->dgBottomMarginTwips;
212     tree->dtY1ReservedTwips=
213 		dgSect->dgPageHighTwips- dgSect->dgFooterPositionTwips;
214 
215     if  ( tree->dtY0ReservedTwips > tree->dtY0UsedTwips )
216 	{ tree->dtY0ReservedTwips=  tree->dtY0UsedTwips;	}
217 
218     return;
219     }
220 
221 /************************************************************************/
222 /*									*/
223 /*  Do a preliminary layout of a document tree.				*/
224 /*									*/
225 /*  Inside the tree, geometry is correct. Some trees are however used	*/
226 /*  in different positions and here we just calculate the layout in	*/
227 /*  order to know the size of the tree to use it in geometry		*/
228 /*  calculations about the document as a whole.				*/
229 /*									*/
230 /*  1)  Remove the bottom of the page master frame. This is the routine	*/
231 /*	that calculates it for future use.				*/
232 /*									*/
233 /************************************************************************/
234 
docTreePrelayout(DocumentTree * tree,const BufferItem * bodySectNode,LayoutJob * lj)235 int docTreePrelayout(		DocumentTree *		tree,
236 				const BufferItem *	bodySectNode,
237 				LayoutJob *		lj )
238     {
239     int				rval= 0;
240     const LayoutContext *	lc= &(lj->ljContext);
241     const DocumentGeometry *	dgSect= &(bodySectNode->biSectDocumentGeometry);
242     LayoutJob			treeLj;
243     LayoutPosition		treeLp;
244 
245     BlockFrame			bf;
246 
247     const int			recursively= 0;
248 
249     docLayoutInitBlockFrame( &bf );
250 
251     docInvalidateTreeLayout( tree );
252 
253     if  ( ! tree->dtRoot )
254 	{ goto ready;	}
255 
256     docDelimitTables( tree->dtRoot, recursively );
257 
258     tree->dtRoot->biSectDocumentGeometry.dgPageWideTwips=
259 						dgSect->dgPageWideTwips;
260     tree->dtRoot->biSectDocumentGeometry.dgLeftMarginTwips=
261 						dgSect->dgLeftMarginTwips;
262     tree->dtRoot->biSectDocumentGeometry.dgRightMarginTwips=
263 						dgSect->dgRightMarginTwips;
264 
265     treeLp.lpPage= tree->dtRoot->biTopPosition.lpPage;
266     treeLp.lpColumn= 0;
267     treeLp.lpPageYTwips= dgSect->dgHeaderPositionTwips;
268     treeLp.lpAtTopOfColumn= 1; /* not really */
269 
270     treeLj= *lj;
271     treeLj.ljChangedRectanglePixels= (DocumentRectangle *)0;
272 
273     treeLj.ljBodySectNode= bodySectNode;
274     treeLj.ljChangedNode= lj->ljChangedNode;
275 
276     docBlockFrameTwips( &bf, tree->dtRoot, lc->lcDocument,
277 					treeLp.lpPage, treeLp.lpColumn );
278     bf.bfContentRect.drY0= treeLp.lpPageYTwips;
279     bf.bfFlowRect.drY0= bf.bfContentRect.drY0;
280 
281     /*  1  */
282     bf.bfContentRect.drY1= dgSect->dgPageHighTwips;
283     bf.bfFlowRect.drY1= bf.bfContentRect.drY1;
284 
285     if  ( docLayoutNodeImplementation( &treeLp, &treeLp,
286 						tree->dtRoot, &bf, &treeLj ) )
287 	{ LDEB(1); rval= -1; goto ready;	}
288 
289     switch( tree->dtRoot->biTreeType )
290 	{
291 	case DOCinFIRST_HEADER:
292 	case DOCinLEFT_HEADER:
293 	case DOCinRIGHT_HEADER:
294 	    docPlaceHeader( tree, dgSect );
295 	    break;
296 
297 	case DOCinFIRST_FOOTER:
298 	case DOCinLEFT_FOOTER:
299 	case DOCinRIGHT_FOOTER:
300 	    docPlaceFooter( tree, dgSect );
301 	    break;
302 
303 	case DOCinFOOTNOTE:
304 	case DOCinENDNOTE:
305 
306 	    /*  temporarily: will be placed later on */
307 	    tree->dtY0UsedTwips= tree->dtRoot->biTopPosition.lpPageYTwips;
308 	    tree->dtY1UsedTwips= tree->dtRoot->biBelowPosition.lpPageYTwips;
309 	    break;
310 
311 	case DOCinFTNSEP:
312 	case DOCinFTNSEPC:
313 	case DOCinFTNCN:
314 	case DOCinAFTNSEP:
315 	case DOCinAFTNSEPC:
316 	case DOCinAFTNCN:
317 
318 	    /*  temporarily */
319 	    tree->dtY0UsedTwips= tree->dtRoot->biTopPosition.lpPageYTwips;
320 	    tree->dtY1UsedTwips= tree->dtRoot->biBelowPosition.lpPageYTwips;
321 	    break;
322 
323 	default:
324 	    LDEB(tree->dtRoot->biTreeType); rval= -1; goto ready;
325 	}
326 
327   ready:
328 
329     docLayoutCleanBlockFrame( &bf );
330 
331     return rval;
332     }
333 
334 /************************************************************************/
335 /*									*/
336 /*  Do the preliminary layout of the headers and footers of a section	*/
337 /*									*/
338 /************************************************************************/
339 
docSectHeaderFooterPrelayout(BufferItem * bodySectNode,LayoutJob * lj)340 int docSectHeaderFooterPrelayout(	BufferItem *	bodySectNode,
341 					LayoutJob *	lj )
342     {
343     int				hdft;
344     int				redraw= 0;
345 
346     for ( hdft= 0; hdft < DOC_HeaderFooterTypeCount; hdft++ )
347 	{
348 	DocumentTree *		dtHdFt;
349 	unsigned char		applies;
350 
351 	int			resY0;
352 	int			resY1;
353 
354 	dtHdFt= docSectionHeaderFooter( bodySectNode, &applies,
355 				    &(lj->ljContext.lcDocument->bdProperties),
356 				    DOC_HeaderFooterTypes[hdft] );
357 	if  ( ! dtHdFt )
358 	    { XDEB(dtHdFt); return -1;	}
359 
360 	resY0= dtHdFt->dtY0ReservedTwips;
361 	resY1= dtHdFt->dtY1ReservedTwips;
362 
363 	if  ( ! dtHdFt->dtRoot || ! applies )
364 	    {
365 	    dtHdFt->dtY0ReservedTwips= 0;
366 	    dtHdFt->dtY1ReservedTwips= 0;
367 	    }
368 	else{
369 	    if  ( docTreePrelayout( dtHdFt, bodySectNode, lj ) )
370 		{ LDEB(1); return -1;	}
371 	    }
372 
373 	if  ( lj->ljChangedRectanglePixels			&&
374 	      ( dtHdFt->dtY0ReservedTwips != resY0	||
375 	        dtHdFt->dtY1ReservedTwips != resY1	)	)
376 	    { redraw++;	}
377 	}
378 
379     if  ( redraw )
380 	{
381 	DocumentRectangle	drPixels;
382 
383 	docGetPixelRectangleForPages( &drPixels, &(lj->ljContext),
384 					bodySectNode->biTopPosition.lpPage,
385 					bodySectNode->biBelowPosition.lpPage );
386 
387 	geoUnionRectangle( lj->ljChangedRectanglePixels,
388 				    lj->ljChangedRectanglePixels, &drPixels );
389 	}
390 
391     return 0;
392     }
393 
394 /************************************************************************/
395 /*									*/
396 /*  Reset page dependent layout administration of headers/footers etc	*/
397 /*  fo force a subsequent recalculation.				*/
398 /*									*/
399 /************************************************************************/
400 
docResetExternalTreeLayout(BufferDocument * bd)401 void docResetExternalTreeLayout(	BufferDocument *	bd )
402     {
403     int		i;
404 
405     docInvalidateTreeLayout( &(bd->bdEiFtnsep) );
406     docInvalidateTreeLayout( &(bd->bdEiFtnsepc) );
407     docInvalidateTreeLayout( &(bd->bdEiFtncn) );
408 
409     docInvalidateTreeLayout( &(bd->bdEiAftnsep) );
410     docInvalidateTreeLayout( &(bd->bdEiAftnsepc) );
411     docInvalidateTreeLayout( &(bd->bdEiAftncn) );
412 
413     for ( i= 0; i < bd->bdBody.dtRoot->biChildCount; i++ )
414 	{
415 	BufferItem *	bodySectNode=  bd->bdBody.dtRoot->biChildren[i];
416 
417 	docInvalidateSectHeaderFooterLayout( bodySectNode );
418 	}
419 
420     return;
421     }
422 
423 /************************************************************************/
424 /*									*/
425 /*  Verify that the root of a selection is formatted for the current	*/
426 /*  page, if not format it.						*/
427 /*									*/
428 /************************************************************************/
429 
docGetY0ForSelectedNoteSeparator(int * pY0Twips,BufferItem ** pBodySectNode,const LayoutContext * lc,const DocumentTree * selTree,int noteItKind,int sepItKind)430 static int docGetY0ForSelectedNoteSeparator(
431 					int *			pY0Twips,
432 					BufferItem **		pBodySectNode,
433 					const LayoutContext *	lc,
434 					const DocumentTree *	selTree,
435 					int			noteItKind,
436 					int			sepItKind )
437     {
438     struct DocumentNote *	dnFirstNote;
439     DocumentTree *		eiBody;
440     DocumentTree *		eiNoteSep;
441     int				y0Twips;
442 
443     DocumentRectangle		drExtern;
444 
445     DocumentField *		dfNote;
446     BufferItem *		bodySectNode;
447 
448     dfNote= docGetFirstNoteInColumn( &dnFirstNote, lc->lcDocument,
449 					    selTree->dtPageSelectedUpon,
450 					    selTree->dtColumnSelectedIn,
451 					    noteItKind );
452     if  ( ! dfNote )
453 	{
454 	LLDEB(selTree->dtPageSelectedUpon,selTree->dtColumnSelectedIn);
455 	return -1;
456 	}
457 
458     if  ( docGetRootOfSelectionScope( &eiBody, &bodySectNode, lc->lcDocument,
459 						&(dfNote->dfSelectionScope) ) )
460 	{ LDEB(1); return -1;	}
461 
462     if  ( docNoteSeparatorRectangle( &drExtern, &eiNoteSep,
463 				    &y0Twips, dnFirstNote, sepItKind, lc ) )
464 	{ LDEB(1); return -1;	}
465 
466     *pY0Twips= y0Twips;
467     *pBodySectNode= bodySectNode;
468     return 0;
469     }
470 
docCheckPageOfSelectedTree(int * pChanged,BufferItem ** pBodySectNode,DocumentRectangle * drChanged,DocumentTree * selTree,const LayoutContext * lc,INIT_LAYOUT_EXTERNAL initLayoutExternal)471 int docCheckPageOfSelectedTree(	int *			pChanged,
472 				BufferItem **		pBodySectNode,
473 				DocumentRectangle *	drChanged,
474 				DocumentTree *		selTree,
475 				const LayoutContext *	lc,
476 				INIT_LAYOUT_EXTERNAL	initLayoutExternal )
477     {
478     int				y0Twips;
479     BufferItem *		selRootBodySectNode= (BufferItem *)0;
480     const SelectionScope *	selRootScope;
481     const int			adjustDocument= 0;
482 
483     if  ( ! selTree->dtRoot )
484 	{ XDEB(selTree->dtRoot); return -1;	}
485 
486     selRootScope= &(selTree->dtRoot->biSectSelectionScope);
487 
488     switch( selTree->dtRoot->biTreeType )
489 	{
490 	case DOCinBODY:
491 	    LDEB(selTree->dtRoot->biTreeType);
492 	    return -1;
493 
494 	case DOCinFIRST_HEADER:
495 	case DOCinLEFT_HEADER:
496 	case DOCinRIGHT_HEADER:
497 
498 	case DOCinFIRST_FOOTER:
499 	case DOCinLEFT_FOOTER:
500 	case DOCinRIGHT_FOOTER:
501 
502 	    selRootBodySectNode= docGetBodySectNodeOfScope( selRootScope,
503 							    lc->lcDocument );
504 
505 	    y0Twips= selTree->dtY0UsedTwips;
506 	    break;
507 
508 	case DOCinFOOTNOTE:
509 	case DOCinENDNOTE:
510 
511 	    selRootBodySectNode= docGetBodySectNodeOfScope( selRootScope,
512 							    lc->lcDocument );
513 
514 	    *pBodySectNode= selRootBodySectNode;
515 	    *pChanged= 0;
516 	    return 0;
517 
518 	case DOCinFTNSEP:
519 
520 	    if  ( selTree->dtPageSelectedUpon < 0 )
521 		{ LDEB(selTree->dtPageSelectedUpon); return -1;	}
522 
523 	    if  ( docGetY0ForSelectedNoteSeparator( &y0Twips,
524 						&selRootBodySectNode,
525 						lc, selTree,
526 						DOCinFOOTNOTE, DOCinFTNSEP ) )
527 		{ LDEB(1); return -1;	}
528 
529 	    break;
530 
531 	case DOCinFTNSEPC:
532 	case DOCinFTNCN:
533 	    LDEB(selTree->dtRoot->biTreeType);
534 	    return -1;
535 
536 	case DOCinAFTNSEP:
537 
538 	    if  ( selTree->dtPageSelectedUpon < 0 )
539 		{ LDEB(selTree->dtPageSelectedUpon); return -1;	}
540 
541 	    if  ( docGetY0ForSelectedNoteSeparator( &y0Twips,
542 						&selRootBodySectNode,
543 						lc, selTree,
544 						DOCinENDNOTE, DOCinAFTNSEP ) )
545 		{ LDEB(1); return -1;	}
546 
547 	    break;
548 
549 	case DOCinAFTNSEPC:
550 	case DOCinAFTNCN:
551 	    SDEB(docTreeTypeStr(selTree->dtRoot->biTreeType));
552 	    return -1;
553 
554 	default:
555 	    LDEB(selTree->dtRoot->biTreeType);
556 	    return -1;
557 	}
558 
559     if  ( selTree->dtPageSelectedUpon < 0 )
560 	{ LSDEB(selTree->dtPageSelectedUpon,docTreeTypeStr(selTree->dtRoot->biTreeType)); return -1;	}
561 
562     if  ( selTree->dtPageFormattedFor == selTree->dtPageSelectedUpon &&
563 	  selTree->dtColumnFormattedFor == selTree->dtColumnSelectedIn )
564 	{
565 	*pBodySectNode= selRootBodySectNode;
566 	*pChanged= 0;
567 	return 0;
568 	}
569 
570     /*  We do not expect the tree to change height here	*/
571     if  ( docLayoutDocumentTree( selTree, drChanged,
572 				    selTree->dtPageSelectedUpon,
573 				    selTree->dtColumnSelectedIn,
574 				    y0Twips, selRootBodySectNode, lc,
575 				    initLayoutExternal, adjustDocument ) )
576 	{ LDEB(selTree->dtPageSelectedUpon); return -1; }
577 
578     *pBodySectNode= selRootBodySectNode;
579     *pChanged= 1; return 0;
580     }
581 
582 /************************************************************************/
583 /*									*/
584 /*  Calculate the layout of a document tree such as a page header or	*/
585 /*  footer. NOT called for the document body.				*/
586 /*									*/
587 /************************************************************************/
588 
docLayoutDocumentTree(DocumentTree * tree,DocumentRectangle * drChanged,int page,int column,int y0Twips,const BufferItem * bodySectNode,const LayoutContext * lc,INIT_LAYOUT_EXTERNAL initLayoutExternal,int adjustDocument)589 int docLayoutDocumentTree(	DocumentTree *		tree,
590 				DocumentRectangle *	drChanged,
591 				int			page,
592 				int			column,
593 				int			y0Twips,
594 				const BufferItem *	bodySectNode,
595 				const LayoutContext *	lc,
596 				INIT_LAYOUT_EXTERNAL	initLayoutExternal,
597 				int			adjustDocument )
598     {
599     int				rval= 0;
600 
601     RecalculateFields		rf;
602     LayoutJob			lj;
603     BlockFrame			bf;
604 
605     LayoutPosition		lpHere;
606 
607     int				oldY1= tree->dtY1UsedTwips;
608 
609     docLayoutInitBlockFrame( &bf );
610     docInitRecalculateFields( &rf );
611     docInitLayoutJob( &lj );
612 
613     if  ( page == tree->dtPageFormattedFor	&&
614 	  column == tree->dtColumnFormattedFor	)
615 	{ goto ready;	}
616 
617     rf.rfDocument= lc->lcDocument;
618     rf.rfCloseObject= lc->lcCloseObject;
619     rf.rfUpdateFlags=
620 	    FIELDdoDOC_FORMATTED|FIELDdoDOC_COMPLETE|FIELDdoPAGE_NUMBER;
621     rf.rfFieldsUpdated= 0;
622     rf.rfBodySectNode= bodySectNode;
623 
624     if  ( docRecalculateTextLevelFieldsInDocumentTree( &rf, tree,
625 						    bodySectNode, page ) )
626 	{ LDEB(page); return -1;	}
627 
628     lpHere.lpPage= page;
629     lpHere.lpColumn= column;
630     lpHere.lpPageYTwips= y0Twips;
631     lpHere.lpAtTopOfColumn= 1; /* not really */
632 
633     lj.ljBodySectNode= bodySectNode;
634 
635     lj.ljChangedRectanglePixels= drChanged;
636     lj.ljContext= *lc;
637     /*
638     lj.ljChangedNode= lc->lcDocument->bdBody.dtRoot;
639     */
640     lj.ljChangedNode= tree->dtRoot;
641 
642     if  ( initLayoutExternal 					&&
643 	  (*initLayoutExternal)( &lj, tree, page, column )	)
644 	{ LDEB(1); rval= -1; goto ready;	}
645 
646     if  ( docLayoutGetInitialFrame( &bf, &lj, &lpHere, tree->dtRoot ) )
647 	{ LDEB(1); return -1;	}
648 
649     docLayoutAdjustFrame( &bf, tree->dtRoot );
650 
651     if  ( docLayoutNodeImplementation( &lpHere, &lpHere,
652 						tree->dtRoot, &bf, &lj ) )
653 	{ LDEB(1); rval= -1; goto ready; }
654 
655     tree->dtPageFormattedFor= page;
656     tree->dtColumnFormattedFor= column;
657     tree->dtY0UsedTwips= y0Twips;
658     tree->dtY1UsedTwips= lpHere.lpPageYTwips;
659 
660     if  ( adjustDocument			&&
661 	  tree->dtY0UsedTwips != oldY1		)
662 	{
663 	const DocumentGeometry * dgSect= &(bodySectNode->biSectDocumentGeometry);
664 	if  ( docIsHeaderType( tree->dtRoot->biTreeType ) )
665 	    {
666 	    docPlaceHeader( tree, dgSect );
667 	    }
668 
669 	if  ( docIsFooterType( tree->dtRoot->biTreeType ) )
670 	    {
671 	    docPlaceFooter( tree, dgSect );
672 	    }
673 
674 	if  ( docAdjustLayoutToChangedTree( &lpHere, tree->dtRoot, &lj ) )
675 	    { LDEB(1); return -1;	}
676 	}
677 
678   ready:
679 
680     docCleanLayoutJob( &lj );
681 
682     return rval;
683     }
684 
685