1 /************************************************************************/
2 /*									*/
3 /*  Paragraph Layout related administration.				*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docLayoutConfig.h"
8 
9 #   include	<stddef.h>
10 #   include	<stdlib.h>
11 
12 #   include	<psFontMetrics.h>
13 #   include	<docPageGrid.h>
14 #   include	"docLayout.h"
15 #   include	"docLayoutObject.h"
16 #   include	"docParagraphLayout.h"
17 #   include	"docRowLayout.h"
18 #   include	<docTreeType.h>
19 #   include	<docTreeNode.h>
20 #   include	<docNodeTree.h>
21 #   include	<docDebug.h>
22 #   include	<docTextParticule.h>
23 #   include	<docPropertiesAdmin.h>
24 
25 #   include	<appDebugon.h>
26 
27 /************************************************************************/
28 
docGetParaTopBorder(BorderProperties * bpTop,int * pNrAbove,int * pFillBefore,const BufferDocument * bd,const BufferItem * paraNode,const BufferItem * cellNode)29 static int docGetParaTopBorder(	BorderProperties *		bpTop,
30 				int *				pNrAbove,
31 				int *				pFillBefore,
32 				const BufferDocument *		bd,
33 				const BufferItem *		paraNode,
34 				const BufferItem *		cellNode )
35     {
36     int				rval= 0;
37     const BufferItem *		prevNode= (const BufferItem *)0;
38 
39     if  ( paraNode->biNumberInParent > 0 )
40 	{ prevNode= cellNode->biChildren[paraNode->biNumberInParent- 1]; }
41 
42     /*  5  */
43     if  ( docBorderNumberIsBorder( bd, paraNode->biParaTopBorderNumber ) )
44 	{
45 	if  ( ! prevNode						||
46 	      prevNode->biParaFrameNumber != paraNode->biParaFrameNumber ||
47 	      prevNode->biParaTopBorderNumber !=
48 					paraNode->biParaTopBorderNumber	)
49 	    {
50 	    docGetBorderPropertiesByNumber( bpTop, bd,
51 					    paraNode->biParaTopBorderNumber );
52 
53 	    *pNrAbove= paraNode->biParaTopBorderNumber;
54 	    rval= 1;
55 	    }
56 
57 	if  ( prevNode							&&
58 	      prevNode->biParaFrameNumber ==
59 				      paraNode->biParaFrameNumber	&&
60 	      prevNode->biParaBottomBorderNumber ==
61 				    paraNode->biParaBottomBorderNumber	)
62 	    { *pFillBefore= 1;	}
63 	}
64 
65     if  ( prevNode							&&
66 	  docShadingNumberIsShading( bd, paraNode->biParaShadingNumber ) &&
67 	  docShadingNumberIsShading( bd, prevNode->biParaShadingNumber ) )
68 	{ *pFillBefore= 1;	}
69 
70     return rval;
71     }
72 
docGetParaBottomBorder(BorderProperties * bpBottom,int * pNrBelow,int * pFillAfter,const BufferDocument * bd,const BufferItem * paraNode,const BufferItem * cellNode)73 static int docGetParaBottomBorder( BorderProperties *		bpBottom,
74 				int *				pNrBelow,
75 				int *				pFillAfter,
76 				const BufferDocument *		bd,
77 				const BufferItem *		paraNode,
78 				const BufferItem *		cellNode )
79     {
80     int				rval= 0;
81     const BufferItem *		nextNode= (const BufferItem *)0;
82 
83     if  ( paraNode->biNumberInParent < cellNode->biChildCount- 1 )
84 	{ nextNode= cellNode->biChildren[paraNode->biNumberInParent+ 1]; }
85 
86     if  ( docBorderNumberIsBorder( bd, paraNode->biParaBottomBorderNumber ) )
87 	{
88 	if  ( ! nextNode						||
89 	      nextNode->biParaFrameNumber != paraNode->biParaFrameNumber ||
90 	      nextNode->biParaBottomBorderNumber !=
91 				    paraNode->biParaBottomBorderNumber	)
92 	    {
93 	    docGetBorderPropertiesByNumber( bpBottom, bd,
94 					paraNode->biParaBottomBorderNumber );
95 
96 	    *pNrBelow= paraNode->biParaBottomBorderNumber;
97 	    rval= 1;
98 	    }
99 
100 	if  ( nextNode							&&
101 	      nextNode->biParaFrameNumber == paraNode->biParaFrameNumber &&
102 	      nextNode->biParaBottomBorderNumber ==
103 				    paraNode->biParaBottomBorderNumber	)
104 	    { *pFillAfter= 1;	}
105 	}
106 
107     if  ( nextNode							&&
108 	  docShadingNumberIsShading( bd, paraNode->biParaShadingNumber ) &&
109 	  docShadingNumberIsShading( bd, nextNode->biParaShadingNumber ) )
110 	{ *pFillAfter= 1;	}
111 
112     return rval;
113     }
114 
115 /************************************************************************/
116 /*									*/
117 /*  Calculate the height of a series of lines in a paragraph.		*/
118 /*									*/
119 /*  1)  The first paragraph in a cell must accomodate space for the	*/
120 /*	top border of the cells of the row and the cell padding.	*/
121 /*  2)  Allocate space for the fattest top border in the row.		*/
122 /*  3)  Allocate space for the row padding.				*/
123 /*  4)  Allocate space for the cell padding.				*/
124 /*  5)  Allocate space for the paragraph top border.			*/
125 /*									*/
126 /************************************************************************/
127 
docLayoutCalculateParaTopInset(const BufferDocument * bd,BufferItem * paraNode)128 void docLayoutCalculateParaTopInset(
129 				const BufferDocument *	bd,
130 				BufferItem *		paraNode )
131     {
132     int				topInset= 0;
133     int				nrAbove= -1;
134     BorderProperties		bpTop;
135     const BufferItem *		cellNode= paraNode->biParent;
136 
137     int				cellMargin= 0;
138     int				fillBefore= 0;
139 
140     topInset= paraNode->biParaSpaceBeforeTwips;
141 
142     /*  1  */
143     if  ( paraNode->biParaTableNesting > 0	&&
144 	  paraNode->biNumberInParent == 0	)
145 	{
146 	const BufferItem *	rowNode= cellNode->biParent;
147 
148 	const RowProperties *	rp= &(rowNode->biRowProperties);
149 	const CellProperties *	cp= rp->rpCells+ cellNode->biNumberInParent;
150 
151 	if  ( ! docIsRowNode( rowNode ) )
152 	    { LDEB(1); cp= (const CellProperties *)0;	}
153 
154 	/*  2  */
155 	cellMargin += rowNode->biRowTopInset;
156 
157 	/*  3  */
158 	switch( rp->rpTopCellPaddingUnit )
159 	    {
160 	    case TRautoNONE:
161 		break;
162 
163 	    case TRautoTWIPS:
164 		cellMargin= rp->rpTopCellPadding;
165 		break;
166 
167 	    default:
168 		LDEB(rp->rpTopCellPaddingUnit);
169 		break;
170 	    }
171 
172 	/*  4  */
173 	if  ( cp ) switch( cp->cpTopPaddingUnit )
174 	    {
175 	    case TRautoNONE:
176 		break;
177 
178 	    case TRautoTWIPS:
179 		cellMargin= cp->cpTopPadding;
180 		break;
181 
182 	    default:
183 		LDEB(cp->cpTopPaddingUnit);
184 		break;
185 	    }
186 	}
187 
188     if  ( paraNode->biParaTableNesting == 0	&&
189 	  paraNode->biNumberInParent == 0	&&
190 	  cellNode->biNumberInParent == 0	)
191 	{
192 	const BufferItem *	rowNode= cellNode->biParent;
193 
194 	topInset += rowNode->biRowTopInset;
195 	}
196 
197     /*  5  */
198     if  ( docGetParaTopBorder( &bpTop, &nrAbove, &fillBefore,
199 						    bd, paraNode, cellNode ) )
200 	{ docAddBorderToInset( &topInset, &bpTop ); 		}
201 
202     paraNode->biParaTopInset= cellMargin+ topInset;
203     paraNode->biParaBorderNrAbove= nrAbove;
204 
205     return;
206     }
207 
docLayoutCalculateParaBottomInset(const BufferDocument * bd,BufferItem * paraNode)208 void docLayoutCalculateParaBottomInset(
209 				    const BufferDocument *	bd,
210 				    BufferItem *		paraNode )
211     {
212     int				bottomInset= 0;
213     int				nrBelow= -1;
214     BorderProperties		bpBottom;
215     const BufferItem *		cellNode= paraNode->biParent;
216     const BufferItem *		rowNode= cellNode->biParent;
217 
218     int				cellMargin= 0;
219     int				fillAfter= 0;
220 
221     if  ( paraNode->biParaTableNesting > 0				&&
222 	  cellNode->biNumberInParent <
223 			    rowNode->biRowProperties.rpCellCount	&&
224 	  paraNode->biNumberInParent == cellNode->biChildCount- 1	)
225 	{
226 	const RowProperties *	rp= &(rowNode->biRowProperties);
227 	const CellProperties *	cp= rp->rpCells+ cellNode->biNumberInParent;
228 
229 	switch( rp->rpBottomCellPaddingUnit )
230 	    {
231 	    case TRautoNONE:
232 		break;
233 
234 	    case TRautoTWIPS:
235 		cellMargin= rp->rpBottomCellPadding;
236 		break;
237 
238 	    default:
239 		LDEB(rp->rpBottomCellPaddingUnit);
240 		break;
241 	    }
242 
243 	switch( cp->cpBottomPaddingUnit )
244 	    {
245 	    case TRautoNONE:
246 		break;
247 
248 	    case TRautoTWIPS:
249 		cellMargin= cp->cpBottomPadding;
250 		break;
251 
252 	    default:
253 		LDEB(cp->cpBottomPaddingUnit);
254 		break;
255 	    }
256 	}
257 
258     if  ( docGetParaBottomBorder( &bpBottom, &nrBelow, &fillAfter,
259 						    bd, paraNode, cellNode ) )
260 	{ docAddBorderToInset( &bottomInset, &bpBottom ); 		}
261 
262     bottomInset += paraNode->biParaSpaceAfterTwips;
263 
264     paraNode->biParaBottomInset= bottomInset+ cellMargin;
265     paraNode->biParaBorderNrBelow= nrBelow;
266 
267     return;
268     }
269 
270 /************************************************************************/
271 /*									*/
272 /*  Determine the 'majority' font of a paragraph, and get the font	*/
273 /*  extents for that font.						*/
274 /*									*/
275 /*  1)  Note that subscript/superscript is NOT taken into account.	*/
276 /*									*/
277 /************************************************************************/
278 
docLayoutParagraphLineExtents(int * pFontSizeTwips,const LayoutContext * lc,BufferItem * paraNode)279 int docLayoutParagraphLineExtents(
280 				int *				pFontSizeTwips,
281 				const LayoutContext *		lc,
282 				BufferItem *			paraNode )
283     {
284     BufferDocument *		bd= lc->lcDocument;
285     const TextParticule *	tp= paraNode->biParaParticules;
286 
287     int				sizeHalfPoints;
288     int				y0= 0;
289     int				y1= 0;
290 
291     int				box;
292     int				part;
293 
294     static int *		counts;
295     int *			fresh;
296 
297     int				found;
298     int				foundCount;
299 
300     DocumentPropertyLists *	dpl= bd->bdPropertyLists;
301     const NumberedPropertiesList * tal= &(dpl->dplTextAttributeList);
302     int				count= tal->nplPagedList.plItemCount;
303 
304     fresh= (int *)realloc( counts, count* sizeof(int) );
305     if  ( ! fresh )
306 	{ LXDEB(count,fresh); return -1;	}
307     counts= fresh;
308 
309     for ( box= 0; box < count; box++ )
310 	{ counts[box]= 0;	}
311 
312     for ( part= 0; part < paraNode->biParaParticuleCount; tp++, part++ )
313 	{
314 	if  ( tp->tpKind != DOCkindSPAN		&&
315 	      tp->tpKind != DOCkindTAB		&&
316 	      tp->tpKind != DOCkindOBJECT	)
317 	    { continue;	}
318 
319 	if  ( tp->tpTextAttrNr < 0			||
320 	      tp->tpTextAttrNr >= count	)
321 	    {
322 	    LLLDEB(part,tp->tpTextAttrNr,count);
323 	    docListNode(0,paraNode,0);
324 	    continue;
325 	    }
326 
327 	counts[tp->tpTextAttrNr] += tp->tpStrlen+ 1;
328 	}
329 
330     found= -1;
331     foundCount= 0;
332     for ( box= 0; box < count; box++ )
333 	{
334 	if  ( counts[box] > foundCount )
335 	    { found= box; foundCount= counts[box];	}
336 	}
337 
338     if  ( found >= 0 )
339 	{
340 	DocumentProperties *	dp= &(bd->bdProperties);
341 	DocumentFontList *	dfl= dp->dpFontList;
342 
343 	TextAttribute			ta;
344 	const AfmFontInfo *		afi;
345 	const IndexSet *		unicodesWanted;
346 
347 	const int			vswap= 1;
348 	DocumentRectangle		drFontBBox;
349 	DocumentRectangle		drFontAscDesc;
350 	int				fontHigh;
351 	int				sizeTwips;
352 
353 	docGetTextAttributeByNumber( &ta, bd, found );
354 
355 	afi= (*lc->lcGetFontForAttribute)( &unicodesWanted,
356 					&ta, dfl, lc->lcPostScriptFontList );
357 	if  ( ! afi )
358 	    { XDEB(afi); return -1;	}
359 
360 	sizeHalfPoints= ta.taFontSizeHalfPoints;
361 	sizeTwips= 10* sizeHalfPoints;
362 
363 	psFontBBox( &drFontBBox, &drFontAscDesc, sizeTwips, vswap, afi );
364 
365 	y0= drFontAscDesc.drY0;
366 	y1= drFontAscDesc.drY1;
367 
368 	/*LINEDISTANCE: scale the position of the baseline based on the bbox */
369 	fontHigh= drFontBBox.drY1- drFontBBox.drY0;
370 	if  ( fontHigh < 2 )
371 	    { LLDEB(ta.taFontSizeHalfPoints,fontHigh); fontHigh= 2;	}
372 	y0= ( drFontBBox.drY0* sizeTwips )/ fontHigh;
373 	y1= ( drFontBBox.drY1* sizeTwips )/ fontHigh;
374 	}
375     else{
376 	/* LDEB(found); */
377 	sizeHalfPoints= 24;
378 	y0= -190;
379 	y1=   50;
380 	}
381 
382     paraNode->biParaMajorityFontSize= sizeHalfPoints;
383     paraNode->biParaMajorityFontAscY0= y0;
384     paraNode->biParaMajorityFontDescY1= y1;
385 
386     *pFontSizeTwips= 10* sizeHalfPoints;
387     return 0;
388     }
389 
390 /************************************************************************/
391 /*									*/
392 /*  Invalidate the layout of all paragraphs in the modified range.	*/
393 /*									*/
394 /************************************************************************/
395 
docInvalidateParagraphLayout(BufferItem * paraNode)396 void docInvalidateParagraphLayout(	BufferItem *	paraNode )
397     {
398     paraNode->biParaLineCount= 0;
399 
400     paraNode->biParaMajorityFontAscY0= 0;
401     paraNode->biParaMajorityFontDescY1= 0;
402     paraNode->biParaMajorityFontSize= 0;
403     }
404 
docInvalidateNodeLayout(BufferItem * node)405 void docInvalidateNodeLayout(		BufferItem *	node )
406     {
407     if  ( node->biLevel == DOClevPARA )
408 	{ docInvalidateParagraphLayout( node );	}
409     else{
410 	int c;
411 
412 	for ( c= 0; c < node->biChildCount; c++ )
413 	    { docInvalidateNodeLayout( node->biChildren[c] );	}
414 	}
415     }
416 
417 /************************************************************************/
418 /*									*/
419 /*  Calculate the top inset after a table.				*/
420 /*									*/
421 /*  This routine is also used to calculate the inset that is used to	*/
422 /*  accomodate space for the bottom border of the previous row. This	*/
423 /*  inset is not used in real rows, but only in the immediate successor	*/
424 /*  of a real row.							*/
425 /*									*/
426 /*  1)  Reserve space for the bottom border of all cells.		*/
427 /*									*/
428 /************************************************************************/
429 
docLayoutCalculateAfterRowTopInset(BufferItem * belowBi,const BufferDocument * bd)430 void docLayoutCalculateAfterRowTopInset(	BufferItem *		belowBi,
431 						const BufferDocument *	bd )
432     {
433     int				col;
434     const BufferItem *		rowNode;
435     const CellProperties *	cp;
436 
437     if  ( belowBi->biNumberInParent == 0 )
438 	{ return;	}
439 
440     rowNode= belowBi->biParent->biChildren[belowBi->biNumberInParent- 1];
441     if  ( ! docIsRowNode( rowNode ) )
442 	{ return;	}
443 
444     belowBi->biRowTopInset= 0;
445 
446     /*  1  */
447     cp= rowNode->biRowCells;
448     for ( col= 0; col < rowNode->biChildCount; cp++, col++ )
449 	{
450 	const int		atRowBottom= 1;
451 	int			useBelow= 0;
452 	BorderProperties	bpBottom;
453 	int			bottomNr;
454 
455 	if  ( CELL_MERGED( cp ) )
456 	    { continue;	}
457 
458 	docGetCellBottomBorder( &bpBottom, &bottomNr, &useBelow, bd, rowNode,
459 							    col, atRowBottom );
460 
461 	{
462 	int rti= belowBi->biRowTopInset;
463 	docStretchInsetForBorder( &rti, &bpBottom );
464 	belowBi->biRowTopInset= rti;
465 	}
466 
467 	}
468 
469     return;
470     }
471 
472 /************************************************************************/
473 /*									*/
474 /*  Determine paragraph border and shading.				*/
475 /*									*/
476 /*  Experimentation with MS-Word revealed that MS-Word includes the	*/
477 /*  space before/after in the borders and shading between two		*/
478 /*  paragraphs if either:						*/
479 /*  a)  Both have the same border.					*/
480 /*  b)  Both have a shading.						*/
481 /*									*/
482 /*  1)	To avoid a trellis effect, we must fill the space above the,	*/
483 /*	paragraph if the paragraph is part of a series of contiguous	*/
484 /*	shaded paragraphs without a border between them.		*/
485 /*  2)	To avoid a trellis effect, we must fill the space below the,	*/
486 /*	paragraph if the paragraph is part of a series of contiguous	*/
487 /*	shaded paragraphs without a border between them.		*/
488 /*									*/
489 /************************************************************************/
490 
docGetParaOrnaments(BlockOrnaments * ornaments,DocumentRectangle * drOutside,DocumentRectangle * drInside,const DocumentRectangle * drParaIn,const BufferDocument * bd,const BufferItem * paraNode,int atParaTop,int atParaBottom)491 void docGetParaOrnaments(
492 			BlockOrnaments *		ornaments,
493 			DocumentRectangle *		drOutside,
494 			DocumentRectangle *		drInside,
495 			const DocumentRectangle *	drParaIn,
496 			const BufferDocument *		bd,
497 			const BufferItem *		paraNode,
498 			int				atParaTop,
499 			int				atParaBottom )
500     {
501     int				thick;
502     int				space;
503 
504     int				nrAbove= -1;
505     BorderProperties		bpTop;
506     int				nrBelow= -1;
507     BorderProperties		bpBottom;
508 
509     DocumentRectangle		drPara= *drParaIn;
510 
511     if  ( atParaTop )
512 	{
513 	int		fillBefore= 0;
514 
515 	docGetParaTopBorder( &bpTop, &nrAbove, &fillBefore,
516 					    bd, paraNode, paraNode->biParent );
517 
518 	/*  1  */
519 	if  ( fillBefore )
520 	    { drPara.drY0 -= paraNode->biParaSpaceBeforeTwips;	}
521 	}
522 
523     if  ( atParaBottom )
524 	{
525 	int		fillAfter= 0;
526 
527 	docGetParaBottomBorder( &bpBottom, &nrBelow, &fillAfter,
528 					    bd, paraNode, paraNode->biParent );
529 
530 	/*  2  */
531 	if  ( fillAfter )
532 	    { drPara.drY1 += paraNode->biParaSpaceAfterTwips;	}
533 	}
534 
535     *drOutside= drPara;
536     *drInside= drPara;
537 
538     if  ( paraNode->biParaShadingNumber != 0 )
539 	{
540 	docGetItemShadingByNumber( &(ornaments->boShading), bd,
541 						paraNode->biParaShadingNumber );
542 
543 	PROPmaskADD( &(ornaments->boPropMask), ORNdrawSHADE );
544 	}
545 
546     docGetBorderPropertiesByNumber( &(ornaments->boLeftBorder), bd,
547 					    paraNode->biParaLeftBorderNumber );
548     docGetBorderPropertiesByNumber( &(ornaments->boRightBorder), bd,
549 					    paraNode->biParaRightBorderNumber );
550 
551     if  ( atParaTop && nrAbove >= 0 )
552 	{
553 	ornaments->boTopBorder= bpTop;
554 	ornaments->boTopBorderNumber= nrAbove;
555 
556 	PROPmaskADD( &(ornaments->boPropMask), ORNdrawTOP_BORDER );
557 
558 	thick= docBorderThick( &space, &(ornaments->boTopBorder) );
559 	/* No! The paragraph above covers the lower one like the
560 	 * tiles on a roof.
561 	drOutside->drY0= drPara->drY0- space- thick;
562 	drInside->drY0= drPara->drY0- space;
563 	*/
564 	drOutside->drY0= drPara.drY0+ space;
565 	drInside->drY0= drPara.drY0+ space+ thick;
566 	}
567 
568     if  ( atParaBottom && nrBelow >= 0 )
569 	{
570 	ornaments->boBottomBorder= bpBottom;
571 	ornaments->boBottomBorderNumber= nrBelow;
572 
573 	PROPmaskADD( &(ornaments->boPropMask), ORNdrawBOTTOM_BORDER );
574 
575 	thick= docBorderThick( &space, &(ornaments->boBottomBorder) );
576 	drInside->drY1= drPara.drY1+ space;
577 	drOutside->drY1= drPara.drY1+ space+ thick;
578 	}
579 
580     if  ( paraNode->biParaLeftBorderNumber != 0 )
581 	{
582 	docGetBorderPropertiesByNumber( &(ornaments->boLeftBorder), bd,
583 					paraNode->biParaLeftBorderNumber );
584 	ornaments->boLeftBorderNumber= paraNode->biParaLeftBorderNumber;
585 
586 	PROPmaskADD( &(ornaments->boPropMask), ORNdrawLEFT_BORDER );
587 
588 	thick= docBorderThick( &space, &(ornaments->boLeftBorder) );
589 	drInside->drX0= drPara.drX0- space;
590 	drOutside->drX0= drPara.drX0- space- thick;
591 	}
592 
593     if  ( paraNode->biParaRightBorderNumber != 0 )
594 	{
595 	docGetBorderPropertiesByNumber( &(ornaments->boRightBorder), bd,
596 					paraNode->biParaRightBorderNumber );
597 	ornaments->boRightBorderNumber= paraNode->biParaRightBorderNumber;
598 
599 	PROPmaskADD( &(ornaments->boPropMask), ORNdrawRIGHT_BORDER );
600 
601 	thick= docBorderThick( &space, &(ornaments->boRightBorder) );
602 	drInside->drX1= drPara.drX1+ space;
603 	drOutside->drX1= drPara.drX1+ space+ thick;
604 	}
605 
606     return;
607     }
608 
609 /************************************************************************/
610 /*									*/
611 /*  Initialisation for paragraph layout.				*/
612 /*									*/
613 /*  1)  Scale objects if necessary. If a scale was chenged, cause the	*/
614 /*	lines in the paragraph to be reformatted. There is no need to	*/
615 /*	completely invalidate the layout: Font related information is	*/
616 /*	unaffected.							*/
617 /*  2)  Calculate global line extent properties if necessary.		*/
618 /*									*/
619 /************************************************************************/
620 
docStartParagraphLayout(const ParagraphFrame * pf,const BlockFrame * bf,BufferItem * paraNode,const LayoutContext * lc)621 static int docStartParagraphLayout(
622 				const ParagraphFrame *		pf,
623 				const BlockFrame *		bf,
624 				BufferItem *			paraNode,
625 				const LayoutContext *		lc )
626     {
627     int				part;
628     const TextParticule *	tp;
629     int				fontSize= 0;
630     int				pageHigh;
631 
632     pageHigh= bf->bfPageGeometry.dgPageHighTwips-
633 			    bf->bfPageGeometry.dgTopMarginTwips-
634 			    bf->bfPageGeometry.dgBottomMarginTwips;
635 
636     /*  1  */
637     tp= paraNode->biParaParticules;
638     for ( part= 0; part < paraNode->biParaParticuleCount; tp++, part++ )
639 	{
640 	InsertedObject *	io;
641 	int			fixed= 0;
642 	int			changed= 0;
643 
644 	if  ( tp->tpKind != DOCkindOBJECT )
645 	    { continue;	}
646 
647 	io= docGetObject( lc->lcDocument, tp->tpObjectNumber );
648 	if  ( ! io )
649 	    { LPDEB(tp->tpObjectNumber,io); continue;	}
650 
651 	if  ( docCheckObjectLayout( &fixed, io ) )
652 	    { LDEB(part); continue;	}
653 
654 	docLayoutScaleObjectToFitParagraphFrame( &changed,
655 				    io, pageHigh, &(pf->pfParaContentRect) );
656 
657 	if  ( fixed || changed )
658 	    {
659 	    if  ( lc->lcCloseObject )
660 		{ (*lc->lcCloseObject)( lc->lcDocument, tp );	}
661 
662 	    paraNode->biParaLineCount= 0;
663 	    }
664 	}
665 
666     /*  2  */
667     if  ( paraNode->biParaMajorityFontSize == 0				&&
668 	  docLayoutParagraphLineExtents( &fontSize, lc, paraNode )	)
669 	{ LDEB(1); return -1;	}
670 
671     docLayoutCalculateParaTopInset( lc->lcDocument, paraNode );
672     docLayoutCalculateParaBottomInset( lc->lcDocument, paraNode );
673 
674     return 0;
675     }
676 
677 /************************************************************************/
678 /*									*/
679 /*  Initialize the formatting of a paragraph by determining its frame	*/
680 /*									*/
681 /************************************************************************/
682 
docLayoutStartParagraph(const LayoutJob * lj,int * pStopCode,BufferItem * paraNode,const BlockFrame * bf,ParagraphLayoutPosition * plp)683 int docLayoutStartParagraph(	const LayoutJob *		lj,
684 				int *				pStopCode,
685 				BufferItem *			paraNode,
686 				const BlockFrame *		bf,
687 				ParagraphLayoutPosition *	plp )
688     {
689     const LayoutContext *	lc= &(lj->ljContext);
690     const BufferItem *		sectBi= paraNode;
691 
692     sectBi= docGetSectNode( paraNode );
693     if  ( ! sectBi )
694 	{ XDEB(sectBi); return -1;	}
695 
696 #   if 0
697     /**
698       * MS-Word does not do this
699       */
700     if  ( paraNode->biParaListOverride > 0				&&
701 	  docAdaptParagraphToListLevel( &indentChanged, paraNode, bd )	)
702 	{ LDEB(1);		}
703 #   endif
704 
705     /*  1  */
706     if  ( paraNode->biTreeType == DOCinBODY			&&
707 	  paraNode->biParaTableNesting == 0			&&
708 	  paraNode->biParaBreakKind != DOCibkNONE		&&
709 	  ! plp->plpPos.lpAtTopOfColumn				)
710 	{
711 	switch( paraNode->biParaBreakKind )
712 	    {
713 	    case DOCibkCOL:
714 		*pStopCode= FORMATstopCOLUMN_BREAK;
715 		break;
716 	    case DOCibkPAGE:
717 		*pStopCode= FORMATstopPAGE_BREAK;
718 		break;
719 
720 	    default:
721 		LDEB(paraNode->biParaBreakKind); return -1;
722 	    }
723 
724 	return 0;
725 	}
726 
727     docParagraphFrameTwips( &(plp->plpParagraphFrame), bf, paraNode );
728 
729     if  ( docStartParagraphLayout( &(plp->plpParagraphFrame),
730 							bf, paraNode, lc ) )
731 	{ LDEB(1); return -1;	}
732 
733     if  ( lj->ljStartScreenParagraph					&&
734 	  (*lj->ljStartScreenParagraph)( paraNode,
735 				    &(plp->plpParagraphFrame), lc )	)
736 	{ LDEB(1); return -1;	}
737 
738     *pStopCode= FORMATstopREADY;
739     return 0;
740     }
741 
742