1 /************************************************************************/
2 /* */
3 /* Layout of a document. */
4 /* */
5 /************************************************************************/
6
7 # include "docLayoutConfig.h"
8
9 # include <stddef.h>
10
11 # include "docLayout.h"
12 # include "docParticuleData.h"
13
14 # include <docDebug.h>
15 # include <appDebugon.h>
16 # include <docObjectProperties.h>
17 # include <docParaParticules.h>
18 # include <docShape.h>
19
20 # define SHOW_LINE_CHANGES 0
21
22 /************************************************************************/
23 /* */
24 /* Layout successive lines of a paragraph. */
25 /* Claim space above a particular line. */
26 /* */
27 /* 2) Do not claim 'space before' at the top of the page. */
28 /* */
29 /************************************************************************/
30
docAboveLine(int * pStopCode,LayoutPosition * lp,const BufferItem * paraNode,int part,const BlockFrame * bf,const ParagraphFrame * pf)31 static int docAboveLine( int * pStopCode,
32 LayoutPosition * lp,
33 const BufferItem * paraNode,
34 int part,
35 const BlockFrame * bf,
36 const ParagraphFrame * pf )
37 {
38 int spaceAboveLineTwips= 0;
39
40 if ( part == 0 )
41 {
42 spaceAboveLineTwips= paraNode->biParaTopInset;
43
44 /* 2 */
45 if ( lp->lpAtTopOfColumn )
46 { spaceAboveLineTwips -= paraNode->biParaSpaceBeforeTwips; }
47 }
48
49 if ( lp->lpPageYTwips+ spaceAboveLineTwips >= bf->bfContentRect.drY1 )
50 { *pStopCode= FORMATstopBLOCK_FULL; return 1; }
51
52 if ( lp->lpPageYTwips+ spaceAboveLineTwips >= pf->pfParaContentRect.drY1 )
53 { *pStopCode= FORMATstopFRAME_FULL; return 1; }
54
55 lp->lpPageYTwips += spaceAboveLineTwips;
56 /* still at top */
57
58 return 0;
59 }
60
61 /************************************************************************/
62 /* */
63 /* Layout successive lines of a paragraph. */
64 /* Claim space below a particular line. */
65 /* */
66 /* Also decide whether it will fit in the current formatting frame. */
67 /* */
68 /* 1) Only use the space after paragraph property and the insets */
69 /* of the table when the paragraph is in a table. */
70 /* 2) Push the position for the next line down until below any shapes */
71 /* on this line. Until we implement the various wrap modes, this */
72 /* is the best we can do. */
73 /* */
74 /************************************************************************/
75
docBelowLine(int * pStopCode,LayoutPosition * lp,const LayoutPosition * lpLineTop,int lineStride,const BufferItem * paraNode,int partFrom,int partUpto,const BlockFrame * bf,const ParagraphFrame * pf,const NotesReservation * nrLine)76 static int docBelowLine( int * pStopCode,
77 LayoutPosition * lp,
78 const LayoutPosition * lpLineTop,
79 int lineStride,
80 const BufferItem * paraNode,
81 int partFrom,
82 int partUpto,
83 const BlockFrame * bf,
84 const ParagraphFrame * pf,
85 const NotesReservation * nrLine )
86 {
87 int spaceBelowLineTwips= 0;
88 int lineBottom;
89 int lineHeight;
90 LayoutPosition lpBelowLine;
91
92 int flowY1WithNotes;
93
94 int footnoteHeight;
95
96 /* 1 */
97 if ( partUpto == paraNode->biParaParticuleCount &&
98 paraNode->biParaTableNesting > 0 &&
99 paraNode->biNumberInParent ==
100 paraNode->biParent->biChildCount- 1 )
101 { spaceBelowLineTwips += paraNode->biParaBottomInset; }
102
103 lpBelowLine= *lpLineTop;
104 lpBelowLine.lpPageYTwips += lineStride;
105 /********************************/
106 /* But add spacing to find */
107 /* position for next line */
108 /********************************/
109
110 lineBottom= lpBelowLine.lpPageYTwips+ spaceBelowLineTwips;
111 lineHeight= lineBottom- lpLineTop->lpPageYTwips;
112
113 footnoteHeight= nrLine->nrFtnsepHeight+ nrLine->nrFootnoteHeight;
114 flowY1WithNotes= bf->bfFlowRect.drY1- footnoteHeight;
115
116 if ( lineBottom > flowY1WithNotes &&
117 lineHeight < bf->bfContentRect.drY1- bf->bfContentRect.drY0 )
118 { *pStopCode= FORMATstopBLOCK_FULL; return 1; }
119
120 if ( lineBottom > pf->pfParaContentRect.drY1 &&
121 lineHeight < pf->pfParaContentRect.drY1- pf->pfParaContentRect.drY0 )
122 { *pStopCode= FORMATstopFRAME_FULL; return 1; }
123
124 *lp= lpBelowLine;
125 lp->lpAtTopOfColumn= 0;
126
127 if ( partUpto == paraNode->biParaParticuleCount )
128 {
129 spaceBelowLineTwips= paraNode->biParaBottomInset;
130
131 lp->lpPageYTwips += spaceBelowLineTwips;
132 lp->lpAtTopOfColumn= 0;
133 }
134
135 return 0;
136 }
137
138 /************************************************************************/
139 /* */
140 /* Calculations on line inserts. */
141 /* */
142 /************************************************************************/
143
docPlaceShape(const BufferItem * paraNode,const LayoutPosition * lpLineTop,InsertedObject * io,const ParagraphFrame * pf,const BlockFrame * bf,int xChar)144 static int docPlaceShape( const BufferItem * paraNode,
145 const LayoutPosition * lpLineTop,
146 InsertedObject * io,
147 const ParagraphFrame * pf,
148 const BlockFrame * bf,
149 int xChar )
150 {
151 DrawingShape * ds= io->ioDrawingShape;
152 int x1;
153 LayoutPosition lpBelowShape;
154
155 if ( ! ds )
156 { XDEB(ds); return -1; }
157
158 docShapePageRectangle( &(io->ioY0Position), &lpBelowShape,
159 &(io->ioX0Twips), &x1,
160 ds, paraNode, lpLineTop, pf, bf, xChar );
161
162 docDrawingShapeInvalidateTextLayout( ds );
163
164 return 0;
165 }
166
docPlaceShapeY(const BufferItem * paraNode,const LayoutPosition * lpLineTop,InsertedObject * io,const BlockFrame * bf)167 static int docPlaceShapeY( const BufferItem * paraNode,
168 const LayoutPosition * lpLineTop,
169 InsertedObject * io,
170 const BlockFrame * bf )
171 {
172 DrawingShape * ds= io->ioDrawingShape;
173 LayoutPosition lpBelowShape;
174
175 BlockFrame bfShape;
176
177 docLayoutInitBlockFrame( &bfShape );
178
179 docShapePageY( &(io->ioY0Position), &lpBelowShape, &bfShape,
180 ds, paraNode, lpLineTop, bf );
181
182 docDrawingShapeInvalidateTextLayout( ds );
183
184 docLayoutCleanBlockFrame( &bfShape );
185
186 return 0;
187 }
188
docPlaceLineInserts(BufferDocument * bd,const BufferItem * paraNode,const TextLine * tl,const ParticuleData * pd,const ParagraphFrame * pf,const BlockFrame * bf,const LayoutPosition * lp)189 static int docPlaceLineInserts( BufferDocument * bd,
190 const BufferItem * paraNode,
191 const TextLine * tl,
192 const ParticuleData * pd,
193 const ParagraphFrame * pf,
194 const BlockFrame * bf,
195 const LayoutPosition * lp )
196 {
197 int i;
198 const TextParticule * tp;
199
200 tp= paraNode->biParaParticules+ tl->tlFirstParticule;
201 for ( i= 0; i < tl->tlParticuleCount; tp++, i++ )
202 {
203 if ( tp->tpKind == DOCkindFIELDHEAD )
204 {
205 if ( docSetPageOfField( &(bd->bdFieldList),
206 tp->tpObjectNumber, lp->lpPage ) )
207 { LDEB(lp->lpPage); docListNode(0,paraNode,0); }
208 }
209
210 if ( tp->tpKind == DOCkindOBJECT )
211 {
212 InsertedObject * io;
213
214 io= docGetObject( bd, tp->tpObjectNumber );
215 if ( ! io )
216 { LPDEB(tp->tpObjectNumber,io); }
217
218 if ( io && io->ioKind == DOCokDRAWING_SHAPE )
219 {
220 if ( docPlaceShape( paraNode, &(tl->tlTopPosition),
221 io, pf, bf, pd->pdX0 ) )
222 { LDEB(1); }
223 }
224 }
225 }
226
227 return 0;
228 }
229
docPlaceLineInsertsY(BufferDocument * bd,const BufferItem * paraNode,const TextLine * tl,const BlockFrame * bf,const LayoutPosition * lp)230 static int docPlaceLineInsertsY(BufferDocument * bd,
231 const BufferItem * paraNode,
232 const TextLine * tl,
233 const BlockFrame * bf,
234 const LayoutPosition * lp )
235 {
236 int i;
237 const TextParticule * tp;
238
239 tp= paraNode->biParaParticules+ tl->tlFirstParticule;
240 for ( i= 0; i < tl->tlParticuleCount; tp++, i++ )
241 {
242 if ( tp->tpKind == DOCkindFIELDHEAD )
243 {
244 docSetPageOfField( &(bd->bdFieldList),
245 tp->tpObjectNumber, lp->lpPage );
246 }
247
248 if ( tp->tpKind == DOCkindOBJECT )
249 {
250 InsertedObject * io;
251
252 io= docGetObject( bd, tp->tpObjectNumber );
253 if ( ! io )
254 { LPDEB(tp->tpObjectNumber,io); }
255
256 if ( io && io->ioKind == DOCokDRAWING_SHAPE )
257 {
258 if ( docPlaceShapeY( paraNode, &(tl->tlTopPosition), io, bf ) )
259 { LDEB(1); }
260 }
261 }
262 }
263
264 return 0;
265 }
266
267 /************************************************************************/
268 /* */
269 /* Layout successive lines of a paragraph. */
270 /* */
271 /* 1) Cope with the output of sgmls: Ignore enormous space before's */
272 /* in footers. */
273 /* */
274 /************************************************************************/
275
docLayout_Line(int * pStopCode,TextLine * resTl,NotesReservation * pNrLine,const BlockFrame * bf,BufferItem * paraNode,int redoLineLayout,int part,ParticuleData * pd,const LayoutJob * lj,const ParagraphFrame * pf,const LayoutPosition * lpTop,LayoutPosition * lpBottom)276 static int docLayout_Line( int * pStopCode,
277 TextLine * resTl,
278 NotesReservation * pNrLine,
279 const BlockFrame * bf,
280 BufferItem * paraNode,
281 int redoLineLayout,
282 int part,
283 ParticuleData * pd,
284 const LayoutJob * lj,
285 const ParagraphFrame * pf,
286 const LayoutPosition * lpTop,
287 LayoutPosition * lpBottom )
288 {
289 const LayoutContext * lc= &(lj->ljContext);
290 BufferDocument * bd= lc->lcDocument;
291
292 int accepted;
293 int res;
294
295 TextParticule * tp= paraNode->biParaParticules+ part;
296
297 TextLine workTl;
298 TextLine * tl= &(workTl);
299
300 LayoutPosition lpHere;
301
302 NotesReservation nrLine;
303
304 lpHere= *lpTop;
305
306 if ( redoLineLayout )
307 {
308 docInitTextLine( tl );
309 tl->tlStroff= tp->tpStroff;
310 }
311 else{
312 workTl= *resTl;
313 }
314 tl->tlFirstParticule= part;
315
316 docInitNotesReservation( &nrLine );
317
318 /* 1 */
319 res= docAboveLine( pStopCode, &lpHere, paraNode, part, bf, pf );
320 if ( res < 0 )
321 { LDEB(res); return -1; }
322 if ( res > 0 )
323 { return 0; }
324
325 tl->tlTopPosition= lpHere;
326 if ( redoLineLayout )
327 { accepted= docLayoutLineBox( tl, paraNode, part, lc, pd, pf ); }
328 else{ accepted= tl->tlParticuleCount; }
329
330 if ( accepted < 1 )
331 { LDEB(accepted); return -1; }
332
333 if ( docLayoutCollectParaFootnoteHeight( &nrLine,
334 tl->tlTopPosition.lpPage, tl->tlTopPosition.lpColumn,
335 bd, lj->ljBodySectNode, paraNode,
336 tl->tlFirstParticule, tl->tlFirstParticule+ accepted ) )
337 { LDEB(1); return -1; }
338
339 res= docBelowLine( pStopCode, &lpHere,
340 &(tl->tlTopPosition), tl->tlLineStride,
341 paraNode, part, part+ accepted,
342 bf, pf, &nrLine );
343 if ( res < 0 )
344 { LDEB(res); return -1; }
345 if ( res > 0 )
346 { return 0; }
347
348 if ( redoLineLayout )
349 {
350 tl->tlStrlen=
351 tp[accepted-1].tpStroff+ tp[accepted-1].tpStrlen- tp->tpStroff;
352 tl->tlParticuleCount= accepted;
353 tl->tlFlowWidthTwips=
354 pf->pfParaContentRect.drX1- pf->pfParaContentRect.drX0;
355
356 if ( lj->ljLayoutScreenLine &&
357 (*lj->ljLayoutScreenLine)( tl, paraNode, lc, pf, pd ) < 0 )
358 { LDEB(accepted); return -1; }
359
360 if ( docPlaceLineInserts( bd, paraNode, tl, pd, pf, bf, &lpHere ) )
361 { LDEB(accepted); }
362 }
363 else{
364 if ( docPlaceLineInsertsY( bd, paraNode, tl, bf, &lpHere ) )
365 { LDEB(accepted); }
366 }
367
368 *lpBottom= lpHere;
369 *pNrLine= nrLine;
370 *resTl= *tl;
371
372 return accepted;
373 }
374
375 /************************************************************************/
376 /* */
377 /* Add the rectangle of the old and the new locations of a line to the */
378 /* rectangle that must be redrawn. */
379 /* */
380 /************************************************************************/
381
docLayoutAddLineToExpose(DocumentRectangle * drChanged,const LayoutJob * lj,const ParagraphFrame * pf,const TextLine * boxLine,const TextLine * tlLine)382 static void docLayoutAddLineToExpose(
383 DocumentRectangle * drChanged,
384 const LayoutJob * lj,
385 const ParagraphFrame * pf,
386 const TextLine * boxLine,
387 const TextLine * tlLine )
388 {
389 const LayoutContext * lc= &(lj->ljContext);
390 DocumentRectangle drBox;
391
392 LayoutPosition lpTop;
393 LayoutPosition lpBottom;
394
395 lpTop= boxLine->tlTopPosition;
396 lpBottom= lpTop;
397 lpBottom.lpPageYTwips += boxLine->tlLineStride;
398
399 docGetPixelRectForPos( &drBox, lc,
400 pf->pfRedrawX0Twips, pf->pfRedrawX1Twips,
401 &lpTop, &lpBottom );
402
403 geoUnionRectangle( drChanged, drChanged, &drBox );
404
405 if ( tlLine )
406 {
407 DocumentRectangle drTl;
408
409 lpTop= tlLine->tlTopPosition;
410 lpBottom= lpTop;
411 lpBottom.lpPageYTwips += tlLine->tlLineStride;
412
413 docGetPixelRectForPos( &drTl, lc,
414 pf->pfRedrawX0Twips, pf->pfRedrawX1Twips,
415 &lpTop, &lpBottom );
416
417 if ( drTl.drX0 != drBox.drX0 ||
418 drTl.drX1 != drBox.drX1 ||
419 drTl.drY0 != drBox.drY0 ||
420 drTl.drY1 != drBox.drY1 )
421 {
422 geoUnionRectangle( drChanged, drChanged, &drTl );
423 geoUnionRectangle( drChanged, drChanged, &drBox );
424
425 # if SHOW_LINE_CHANGES
426 appDebug( "EXPOSE [%4d..%4d x %4d..%4d]\n",
427 drChanged->drX0, drChanged->drX1,
428 drChanged->drY0, drChanged->drY1 );
429 # endif
430 }
431 }
432 else{
433 geoUnionRectangle( drChanged, drChanged, &drBox );
434
435 # if SHOW_LINE_CHANGES
436 appDebug( "EXPOSE [%4d..%4d x %4d..%4d]\n",
437 drChanged->drX0, drChanged->drX1,
438 drChanged->drY0, drChanged->drY1 );
439 # endif
440 }
441 }
442
443 /************************************************************************/
444 /* */
445 /* Layout a series of lines in a paragraph. */
446 /* */
447 /* 1) Make sure that we have scratch space for the layout routines. */
448 /* 2) As long as there are any particules to be placed/formatted */
449 /* 3) Can the current line be reused? */
450 /* 4) If so just place it at a new position. */
451 /* 5) Otherwise recalculate layout. */
452 /* 6) If the line does not fit on this page (column) stop. */
453 /* 7) Cause the line to be redrawn if either it is reformatted, or it */
454 /* is moved. */
455 /* 8) Subtract the space needed for the footnotes in this line from */
456 /* the space left on this page. (column) */
457 /* 9) Insert into administration. */
458 /* 10) If the line ends in a page break, make sure nothing will fit on */
459 /* this page (in this column) anymore. */
460 /* 11) Truncate the number of lines when the paragraph is completely */
461 /* formatted. */
462 /* */
463 /************************************************************************/
464
docLayoutParaLines(int * pStopCode,int isRedo,const ParagraphFrame * pf,LayoutPosition * lpHere,int * pLine,BlockFrame * bf,const LayoutJob * lj,BufferItem * paraNode,int part)465 int docLayoutParaLines( int * pStopCode,
466 int isRedo,
467 const ParagraphFrame * pf,
468 LayoutPosition * lpHere,
469 int * pLine,
470 BlockFrame * bf,
471 const LayoutJob * lj,
472 BufferItem * paraNode,
473 int part )
474 {
475 int stopCode= FORMATstopREADY;
476
477 int line= (*pLine);
478 int done= 0;
479
480 ParticuleData * pd;
481
482 LayoutPosition lp= (*lpHere);
483
484 /* 1 */
485 if ( docPsClaimParticuleData( paraNode->biParaParticuleCount, &pd ) )
486 { LDEB(paraNode->biParaParticuleCount); return -1; }
487
488 /* 2 */
489 while( part < paraNode->biParaParticuleCount )
490 {
491 int accepted;
492 TextLine boxLine;
493
494 int placeOldLine= 0;
495 TextLine * tlLine= (TextLine *)0;
496
497 NotesReservation nrLine;
498
499 DocumentRectangle * drChanged= lj->ljChangedRectanglePixels;
500
501 int flowWidth;
502
503 docInitNotesReservation( &nrLine );
504
505 flowWidth= pf->pfParaContentRect.drX1- pf->pfParaContentRect.drX0;
506
507 docInitTextLine( &boxLine );
508
509 /* 3 */
510 if ( line < paraNode->biParaLineCount )
511 {
512 const TextParticule * tp= paraNode->biParaParticules+ part;
513
514 tlLine= paraNode->biParaLines+ line;
515 placeOldLine= 1;
516 boxLine= *tlLine;
517
518 if ( tlLine->tlFirstParticule+ tlLine->tlParticuleCount >
519 paraNode->biParaParticuleCount ||
520 tlLine->tlStroff != tp->tpStroff ||
521 tlLine->tlFlowWidthTwips != flowWidth )
522 { placeOldLine= 0; }
523 }
524
525 /* 4, 5 */
526 accepted= docLayout_Line( &stopCode, &boxLine, &nrLine, bf,
527 paraNode, ! placeOldLine, part, pd, lj, pf, &lp, &lp );
528
529 if ( accepted < 0 )
530 { LDEB(accepted); return -1; }
531
532 /* 6 */
533 if ( accepted == 0 )
534 { break; }
535
536 /* 7 */
537 if ( drChanged )
538 {
539 docLayoutAddLineToExpose( drChanged, lj, pf, &boxLine, tlLine );
540 }
541
542 /* 8 */
543 if ( ! isRedo )
544 { docLayoutReserveNoteHeight( bf, &nrLine ); }
545
546 /* 9 */
547 if ( line >= paraNode->biParaLineCount )
548 {
549 tlLine= docInsertTextLine( paraNode, -1 );
550 if ( ! tlLine )
551 { XDEB(tlLine); return -1; }
552 }
553 else{
554 tlLine= paraNode->biParaLines+ line;
555 }
556
557 *tlLine= boxLine;
558
559 part += accepted; done += accepted; line++;
560
561 /* 10 */
562 if ( boxLine.tlFlags & TLflagBLOCKBREAK )
563 {
564 int part;
565
566 part= boxLine.tlFirstParticule+ boxLine.tlParticuleCount- 1;
567
568 switch( paraNode->biParaParticules[part].tpKind )
569 {
570 case DOCkindPAGEBREAK:
571 stopCode= FORMATstopPAGE_BREAK;
572 break;
573 case DOCkindCOLUMNBREAK:
574 stopCode= FORMATstopCOLUMN_BREAK;
575 break;
576 default:
577 LDEB(paraNode->biParaParticules[part].tpKind);
578 stopCode= FORMATstopPAGE_BREAK;
579 break;
580 }
581 break;
582 }
583 }
584
585 *pLine= line;
586 *lpHere= lp;
587 *pStopCode= stopCode;
588
589 /* 11 */
590 if ( part >= paraNode->biParaParticuleCount &&
591 paraNode->biParaLineCount > line )
592 { paraNode->biParaLineCount= line; }
593
594 return done;
595 }
596
597