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