1 /************************************************************************/
2 /*									*/
3 /*  Layout of a document.						*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docLayoutConfig.h"
8 
9 #   include	<stddef.h>
10 #   include	<limits.h>
11 
12 #   include	"docLayout.h"
13 #   include	<docPageGrid.h>
14 #   include	<docTreeType.h>
15 #   include	<docTreeNode.h>
16 #   include	<docNodeTree.h>
17 #   include	<docTreeScanner.h>
18 
19 #   include	<appDebugon.h>
20 
21 /************************************************************************/
22 /*									*/
23 /*  Initialize a layout job.						*/
24 /*									*/
25 /************************************************************************/
26 
docInitLayoutJob(LayoutJob * lj)27 void docInitLayoutJob(	LayoutJob *	lj )
28     {
29     lj->ljChangedRectanglePixels= (DocumentRectangle *)0;
30     layoutInitContext( &(lj->ljContext) );
31     lj->ljChangedNode= (struct BufferItem *)0;
32     lj->ljReachedDocumentBottom= 0;
33 
34     lj->ljBalancePage= -1;
35     lj->ljBalanceY1= 0;
36 
37     lj->ljBodySectNode= (const struct BufferItem *)0;
38 
39     lj->ljStartScreenParagraph= (START_SCREEN_PARAGRAPH)0;
40     lj->ljLayoutScreenLine= (LAYOUT_SCREEN_LINE)0;
41 
42     return;
43     }
44 
docCleanLayoutJob(LayoutJob * lj)45 void docCleanLayoutJob(	LayoutJob *	lj )
46     {
47     return;
48     }
49 
50 /************************************************************************/
51 /*									*/
52 /*  Invalidate the layout of all paragraphs in the modified range.	*/
53 /*									*/
54 /************************************************************************/
55 
docInvalidateChangedLayout(BufferItem * node,const DocumentSelection * ds,const BufferItem * bodySectNode,void * through)56 static int docInvalidateChangedLayout(
57 				BufferItem *			node,
58 				const DocumentSelection *	ds,
59 				const BufferItem *		bodySectNode,
60 				void *				through )
61     {
62     if  ( node->biLevel == DOClevPARA )
63 	{ docInvalidateParagraphLayout( node );	}
64 
65     return ADVICEtsOK;
66     }
67 
68 /************************************************************************/
69 /*									*/
70 /*  Redo layout of the relevant part of the document after editing.	*/
71 /*									*/
72 /************************************************************************/
73 
docLayoutInvalidateRange(DocumentSelection * dsLayout,BufferDocument * bd,const DocumentTree * ei,EditRange * er)74 int docLayoutInvalidateRange(	DocumentSelection *	dsLayout,
75 				BufferDocument *	bd,
76 				const DocumentTree *	ei,
77 				EditRange *		er )
78     {
79     const int		direction= 1;
80     const int		flags= 0;
81     DocumentPosition	dpHead;
82     DocumentPosition	dpTail;
83 
84     if  ( er->erHead.epParaNr == 0 )
85 	{
86 	LDEB(er->erHead.epParaNr);
87 	er->erHead.epParaNr= 1;
88 	}
89 
90     {
91     BufferItem *	headNode;
92 
93     headNode= docGetParagraphByNumber( ei, er->erHead.epParaNr );
94 
95     if  ( headNode )
96 	{
97 	if  ( docHeadPosition( &dpHead, headNode ) )
98 	    { LDEB(er->erHead.epParaNr); return -1;	}
99 	}
100     else{
101 	/*LXDEB(er->erHead.epParaNr,headNode);*/
102 	if  ( docHeadPosition( &dpHead, ei->dtRoot ) )
103 	    { LDEB(er->erHead.epParaNr); return -1;	}
104 	}
105     }
106 
107     {
108     BufferItem *	tailNode;
109 
110     tailNode= docGetParagraphByNumber( ei, er->erTail.epParaNr );
111 
112     if  ( tailNode )
113 	{
114 	if  ( docTailPosition( &dpTail, tailNode ) )
115 	    { LDEB(er->erTail.epParaNr); return -1;	}
116 	}
117     else{
118 	/* LXDEB(er->erTail.epParaNr,tailNode); */
119 	if  ( docTailPosition( &dpTail, ei->dtRoot ) )
120 	    { LDEB(er->erTail.epParaNr); return -1;		}
121 	}
122     }
123 
124     docInitDocumentSelection( dsLayout );
125     docSetRangeSelection( dsLayout, &dpHead, &dpTail, direction );
126 
127     if  ( docScanSelection( bd, dsLayout, docInvalidateChangedLayout,
128 				    (NodeVisitor)0, flags, (void *)0 ) < 0 )
129 	{ LDEB(1); return -1;	}
130 
131     return 0;
132     }
133 
134 /************************************************************************/
135 /*									*/
136 /*  Determine the frame when a formatting task is (re) started for a	*/
137 /*  buffer item.							*/
138 /*									*/
139 /*  2)  Calculate the frame in which the text is to be laid out.	*/
140 /*  3)  If the preceding paragraph ends on the same page where this	*/
141 /*	nodes begins, reserve space for the footnotes upto the		*/
142 /*	beginning of this block and subtract the footnote height from	*/
143 /*	the buttom of the frame.					*/
144 /*									*/
145 /************************************************************************/
146 
docLayoutGetInitialFrame(BlockFrame * bf,const LayoutJob * lj,const LayoutPosition * lpHere,BufferItem * node)147 int docLayoutGetInitialFrame(		BlockFrame *		bf,
148 					const LayoutJob *	lj,
149 					const LayoutPosition *	lpHere,
150 					BufferItem *		node )
151     {
152     const LayoutContext *	lc= &(lj->ljContext);
153     BufferDocument *		bd= lc->lcDocument;
154     const BufferItem *		prevParaBi= (const BufferItem *)0;
155 
156     /*  2  */
157     docBlockFrameTwips( bf, node, bd, lpHere->lpPage, lpHere->lpColumn );
158 
159     /*  3  */
160     if  ( node->biTreeType == DOCinBODY )
161 	{ prevParaBi= docPrevParagraph( node );	}
162 
163     if  ( prevParaBi						&&
164 	  prevParaBi->biBelowPosition.lpPage >= lpHere->lpPage	)
165 	{
166 	DocumentPosition		dpHere;
167 	int				partHere;
168 
169 	if  ( docHeadPosition( &dpHere, node ) )
170 	    { LDEB(1); return -1;	}
171 	partHere= 0;
172 
173 	if  ( docCollectFootnotesFromColumn( bf, &dpHere, partHere, bd,
174 					lpHere->lpPage, lpHere->lpColumn ) )
175 	    { LDEB(lpHere->lpPage); return -1;	}
176 	}
177 
178     return 0;
179     }
180 
181 /************************************************************************/
182 /*									*/
183 /*  Adjust the bottom of a node to changes inside.			*/
184 /*									*/
185 /************************************************************************/
186 
docLayoutSetBottomPosition(int * pChanged,LayoutPosition * lpBelow,const LayoutPosition * lp,const LayoutContext * lc,DocumentRectangle * drChanged)187 void docLayoutSetBottomPosition( int *				pChanged,
188 				LayoutPosition *		lpBelow,
189 				const LayoutPosition *		lp,
190 				const LayoutContext *		lc,
191 				DocumentRectangle *		drChanged )
192     {
193     int			changed= 0;
194 
195     int			oldY1Pixels;
196     int			newY1Pixels;
197 
198     oldY1Pixels= docLayoutYPixels( lc, lpBelow );
199 
200     if  ( ! DOC_SAME_POSITION( lpBelow, lp ) )
201 	{ *lpBelow= *lp; changed= 1; }
202 
203     newY1Pixels= docLayoutYPixels( lc, lp );
204 
205     if  ( oldY1Pixels < newY1Pixels )
206 	{
207 	if  ( drChanged					&&
208 	      drChanged->drY1 < newY1Pixels -1	)
209 	    { drChanged->drY1=  newY1Pixels -1;	}
210 	}
211 
212     if  ( oldY1Pixels > newY1Pixels )
213 	{
214 	if  ( drChanged							&&
215 	      drChanged->drY1 < oldY1Pixels- 1	)
216 	    { drChanged->drY1=  oldY1Pixels- 1;	}
217 	}
218 
219     /* or */
220     if  ( pChanged && changed )
221 	{ *pChanged= changed;	}
222 
223     return;
224     }
225 
docLayoutSetNodeBottom(int * pChanged,BufferItem * node,const LayoutPosition * lp,const LayoutContext * lc,DocumentRectangle * drChanged)226 void docLayoutSetNodeBottom(	int *			pChanged,
227 				BufferItem *		node,
228 				const LayoutPosition *	lp,
229 				const LayoutContext *	lc,
230 				DocumentRectangle *	drChanged )
231     {
232     docLayoutSetBottomPosition( pChanged, &(node->biBelowPosition),
233 							lp, lc, drChanged );
234     }
235 
236 /************************************************************************/
237 /*									*/
238 /*  Start/Finish the layout of items: Is done around the node type	*/
239 /*  specific layout procedures.						*/
240 /*									*/
241 /************************************************************************/
242 
docLayoutStartNodeLayout(BufferItem * node,const LayoutJob * lj,const LayoutPosition * lpHere)243 void docLayoutStartNodeLayout(	BufferItem *		node,
244 				const LayoutJob *	lj,
245 				const LayoutPosition *	lpHere )
246     {
247     const LayoutContext *	lc= &(lj->ljContext);
248     DocumentRectangle *		drChanged= lj->ljChangedRectanglePixels;
249     int				y0;
250     int				y1;
251 
252     y0= docLayoutYPixels( lc, &(node->biTopPosition) );
253     y1= docLayoutYPixels( lc, &(node->biBelowPosition) )- 1;
254 
255     if  ( drChanged		&&
256 	  drChanged->drY0 > y0	)
257 	{ drChanged->drY0=  y0;	}
258 
259     node->biTopPosition= *lpHere;
260 
261     if  ( drChanged )
262 	{
263 	y0= docLayoutYPixels( lc, &(node->biTopPosition) );
264 
265 	if  ( drChanged->drY0 > y0 )
266 	    { drChanged->drY0=  y0;			}
267 	if  ( drChanged->drY1 < y1 )
268 	    { drChanged->drY1=  y1;	}
269 	}
270 
271     return;
272     }
273 
docLayoutFinishNodeLayout(int * pChanged,BufferItem * node,const LayoutJob * lj,const LayoutPosition * lpHere)274 void docLayoutFinishNodeLayout(	int *			pChanged,
275 				BufferItem *		node,
276 				const LayoutJob *	lj,
277 				const LayoutPosition *	lpHere )
278     {
279     docLayoutSetBottomPosition( pChanged, &(node->biBelowPosition),
280 		    lpHere, &(lj->ljContext), lj->ljChangedRectanglePixels );
281 
282     return;
283     }
284 
285 /************************************************************************/
286 /*									*/
287 /*  Find the first section on a particular page.			*/
288 /*									*/
289 /************************************************************************/
290 
docGetFirstSectionOnPage(BufferDocument * bd,int page)291 int docGetFirstSectionOnPage(		BufferDocument *	bd,
292 					int			page )
293     {
294     BufferItem *		bodyNode= bd->bdBody.dtRoot;
295     int				sectNr;
296 
297     for ( sectNr= 0; sectNr < bodyNode->biChildCount; sectNr++ )
298 	{
299 	const BufferItem *	bodySectNode= bodyNode->biChildren[sectNr];
300 
301 	if  ( bodySectNode->biTopPosition.lpPage <= page	&&
302 	      bodySectNode->biBelowPosition.lpPage >= page	)
303 	    { return sectNr;	}
304 	}
305 
306     return -1;
307     }
308 
309 /************************************************************************/
310 /*									*/
311 /*  Adapt the bottom of a block frame to avoid page breaks in trees	*/
312 /*  that can not hold one.						*/
313 /*									*/
314 /************************************************************************/
315 
docLayoutAdjustFrame(BlockFrame * bf,const BufferItem * node)316 void docLayoutAdjustFrame(	BlockFrame *		bf,
317 				const BufferItem *	node )
318     {
319     /*  4  */
320     if  ( node->biTreeType == DOCinFOOTNOTE		||
321 	  docIsSeparatorType( node->biTreeType )	||
322 	  docIsHeaderType( node->biTreeType )		||
323 	  docIsFooterType( node->biTreeType )		)
324 	{
325 	bf->bfContentRect.drY1= INT_MAX;
326 	bf->bfFlowRect.drY1= INT_MAX;
327 	}
328 
329     return;
330     }
331