1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include <hintids.hxx>
29 #include <editeng/keepitem.hxx>
30 #include <editeng/hyznitem.hxx>
31 #include <pagefrm.hxx> // ChangeFtnRef
32 #include <ndtxt.hxx> // MakeFrm()
33 #include <dcontact.hxx> // SwDrawContact
34 #include <dflyobj.hxx> // SwVirtFlyDrawObj
35 #include <flyfrm.hxx>
36 #include <ftnfrm.hxx> // SwFtnFrm
37 #include <txtftn.hxx>
38 #include <fmtftn.hxx>
39 #include <paratr.hxx>
40 #include <viewopt.hxx> // SwViewOptions
41 #include <viewsh.hxx> // ViewShell
42 #include <frmatr.hxx>
43 #include <pam.hxx>
44 #include <flyfrms.hxx>
45 #include <fmtanchr.hxx>
46 #include <txtcfg.hxx>
47 #include <itrform2.hxx> // SwTxtFormatter
48 #include <widorp.hxx> // Widows and Orphans
49 #include <txtcache.hxx>
50 #include <porrst.hxx> // SwEmptyPortion
51 #include <blink.hxx> // pBlink
52 #include <porfld.hxx> // SwFldPortion
53 #include <sectfrm.hxx> // SwSectionFrm
54 #include <pormulti.hxx> // SwMultiPortion
55
56 #include <rootfrm.hxx>
57 #include <frmfmt.hxx> // SwFrmFmt
58 // OD 2004-05-24 #i28701#
59 #include <sortedobjs.hxx>
60 #include <portab.hxx>
61 #include <editeng/lrspitem.hxx>
62 #include <editeng/tstpitem.hxx>
63
64 class FormatLevel
65 {
66 static MSHORT nLevel;
67 public:
FormatLevel()68 inline FormatLevel() { ++nLevel; }
~FormatLevel()69 inline ~FormatLevel() { --nLevel; }
GetLevel() const70 inline MSHORT GetLevel() const { return nLevel; }
LastLevel()71 static sal_Bool LastLevel() { return 10 < nLevel; }
72 };
73 MSHORT FormatLevel::nLevel = 0;
74
75 /*************************************************************************
76 * ValidateTxt/Frm()
77 *************************************************************************/
78
ValidateTxt(SwFrm * pFrm)79 void ValidateTxt( SwFrm *pFrm ) // Freund vom Frame
80 {
81 if ( ( ! pFrm->IsVertical() &&
82 pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
83 ( pFrm->IsVertical() &&
84 pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) )
85 pFrm->bValidSize = sal_True;
86 /*
87 pFrm->bValidPrtArea = sal_True;
88 //Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren.
89 //Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate
90 //validiert werden.
91 if ( !pFrm->bValidPos )
92 {
93 //Leider muessen wir dazu die korrekte Position berechnen.
94 Point aOld( pFrm->Frm().Pos() );
95 pFrm->MakePos();
96 if ( aOld != pFrm->Pos() )
97 {
98 pFrm->Frm().Pos( aOld );
99 pFrm->bValidPos = sal_False;
100 }
101 }
102 */
103 }
104
ValidateFrm()105 void SwTxtFrm::ValidateFrm()
106 {
107 // Umgebung validieren, um Oszillationen zu verhindern.
108 SWAP_IF_SWAPPED( this )
109
110 if ( !IsInFly() && !IsInTab() )
111 { //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich
112 //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von
113 //Flys nicht. Fix fuer 5544
114 SwSectionFrm* pSct = FindSctFrm();
115 if( pSct )
116 {
117 if( !pSct->IsColLocked() )
118 pSct->ColLock();
119 else
120 pSct = NULL;
121 }
122
123 SwFrm *pUp = GetUpper();
124 pUp->Calc();
125 if( pSct )
126 pSct->ColUnlock();
127 }
128 ValidateTxt( this );
129
130 //MA: mindestens das MustFit-Flag muessen wir retten!
131 ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." );
132 SwParaPortion *pPara = GetPara();
133 const sal_Bool bMustFit = pPara->IsPrepMustFit();
134 ResetPreps();
135 pPara->SetPrepMustFit( bMustFit );
136
137 UNDO_SWAP( this )
138 }
139
140 /*************************************************************************
141 * ValidateBodyFrm()
142 *************************************************************************/
143
144 // nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert
145 // werden, damit die DeadLine richtig sitzt.
146 // Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert.
147
_ValidateBodyFrm(SwFrm * pFrm)148 void _ValidateBodyFrm( SwFrm *pFrm )
149 {
150 if( pFrm && !pFrm->IsCellFrm() )
151 {
152 if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
153 _ValidateBodyFrm( pFrm->GetUpper() );
154 if( !pFrm->IsSctFrm() )
155 pFrm->Calc();
156 else
157 {
158 sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
159 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
160 pFrm->Calc();
161 if( !bOld )
162 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
163 }
164 }
165 }
166
ValidateBodyFrm()167 void SwTxtFrm::ValidateBodyFrm()
168 {
169 SWAP_IF_SWAPPED( this )
170
171 //siehe Kommtar in ValidateFrm()
172 if ( !IsInFly() && !IsInTab() &&
173 !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
174 _ValidateBodyFrm( GetUpper() );
175
176 UNDO_SWAP( this )
177 }
178
179 /*************************************************************************
180 * SwTxtFrm::FindBodyFrm()
181 *************************************************************************/
182
_GetDropRect(SwRect & rRect) const183 sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
184 {
185 SWAP_IF_NOT_SWAPPED( this )
186
187 ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
188 SwTxtSizeInfo aInf( (SwTxtFrm*)this );
189 SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
190 if( aLine.GetDropLines() )
191 {
192 rRect.Top( aLine.Y() );
193 rRect.Left( aLine.GetLineStart() );
194 rRect.Height( aLine.GetDropHeight() );
195 rRect.Width( aLine.GetDropLeft() );
196
197 if ( IsRightToLeft() )
198 SwitchLTRtoRTL( rRect );
199
200 if ( IsVertical() )
201 SwitchHorizontalToVertical( rRect );
202 UNDO_SWAP( this )
203 return sal_True;
204 }
205
206 UNDO_SWAP( this )
207
208 return sal_False;
209 }
210
211 /*************************************************************************
212 * SwTxtFrm::FindBodyFrm()
213 *************************************************************************/
214
FindBodyFrm() const215 const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
216 {
217 if ( IsInDocBody() )
218 {
219 const SwFrm *pFrm = GetUpper();
220 while( pFrm && !pFrm->IsBodyFrm() )
221 pFrm = pFrm->GetUpper();
222 return (const SwBodyFrm*)pFrm;
223 }
224 return 0;
225 }
226
227 /*************************************************************************
228 * SwTxtFrm::CalcFollow()
229 *************************************************************************/
230
CalcFollow(const xub_StrLen nTxtOfst)231 sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
232 {
233 SWAP_IF_SWAPPED( this )
234
235 ASSERT( HasFollow(), "CalcFollow: missing Follow." );
236
237 SwTxtFrm* pMyFollow = GetFollow();
238
239 SwParaPortion *pPara = GetPara();
240 sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;
241
242 if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
243 bFollowFld || pMyFollow->IsFieldFollow() ||
244 ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
245 ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
246 {
247 #ifdef DBG_UTIL
248 const SwFrm *pOldUp = GetUpper();
249 #endif
250
251 SWRECTFN ( this )
252 SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
253 SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();
254
255 const SwPageFrm *pPage = 0;
256 sal_Bool bOldInvaCntnt = sal_True;
257 if ( !IsInFly() && GetNext() )
258 {
259 pPage = FindPageFrm();
260 //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u.
261 bOldInvaCntnt = pPage->IsInvalidCntnt();
262 }
263
264 pMyFollow->_SetOfst( nTxtOfst );
265 pMyFollow->SetFieldFollow( bFollowFld );
266 if( HasFtn() || pMyFollow->HasFtn() )
267 {
268 ValidateFrm();
269 ValidateBodyFrm();
270 if( pPara )
271 {
272 *(pPara->GetReformat()) = SwCharRange();
273 *(pPara->GetDelta()) = 0;
274 }
275 }
276
277 //Der Fussnotenbereich darf sich keinesfalls vergrossern.
278 SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );
279
280 pMyFollow->CalcFtnFlag();
281 if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
282 nOldBottom = bVert ? 0 : LONG_MAX;
283
284 while( sal_True )
285 {
286 if( !FormatLevel::LastLevel() )
287 {
288 // Weenn der Follow in einem spaltigen Bereich oder einem
289 // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert
290 // werden, da das FormatWidthCols() nicht funktioniert, wenn
291 // es aus dem MakeAll des _gelockten_ Follows heraus gerufen
292 // wird.
293 SwSectionFrm* pSct = pMyFollow->FindSctFrm();
294 if( pSct && !pSct->IsAnLower( this ) )
295 {
296 if( pSct->GetFollow() )
297 pSct->SimpleFormat();
298 else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
299 ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
300 break;
301 }
302 // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
303 if ( FollowFormatAllowed() )
304 {
305 // OD 14.03.2003 #i11760# - no nested format of follows, if
306 // text frame is contained in a column frame.
307 // Thus, forbid intrinsic format of follow.
308 {
309 bool bIsFollowInColumn = false;
310 SwFrm* pFollowUpper = pMyFollow->GetUpper();
311 while ( pFollowUpper )
312 {
313 if ( pFollowUpper->IsColumnFrm() )
314 {
315 bIsFollowInColumn = true;
316 break;
317 }
318 if ( pFollowUpper->IsPageFrm() ||
319 pFollowUpper->IsFlyFrm() )
320 {
321 break;
322 }
323 pFollowUpper = pFollowUpper->GetUpper();
324 }
325 if ( bIsFollowInColumn )
326 {
327 pMyFollow->ForbidFollowFormat();
328 }
329 }
330
331 pMyFollow->Calc();
332 // Der Follow merkt anhand seiner Frm().Height(), dass was schief
333 // gelaufen ist.
334 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
335 if( pMyFollow->GetPrev() )
336 {
337 pMyFollow->Prepare( PREP_CLEAR );
338 pMyFollow->Calc();
339 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
340 }
341
342 // OD 14.03.2003 #i11760# - reset control flag for follow format.
343 pMyFollow->AllowFollowFormat();
344 }
345
346 //Sicherstellen, dass der Follow gepaintet wird.
347 pMyFollow->SetCompletePaint();
348 }
349
350 pPara = GetPara();
351 //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er
352 //diese und wird erneut formatiert, falls moeglich.
353 if( pPara && pPara->IsPrepWidows() )
354 CalcPreps();
355 else
356 break;
357 }
358
359 if( HasFtn() || pMyFollow->HasFtn() )
360 {
361 ValidateBodyFrm();
362 ValidateFrm();
363 if( pPara )
364 {
365 *(pPara->GetReformat()) = SwCharRange();
366 *(pPara->GetDelta()) = 0;
367 }
368 }
369
370 if ( pPage )
371 {
372 if ( !bOldInvaCntnt )
373 pPage->ValidateCntnt();
374 }
375
376 #ifdef DBG_UTIL
377 ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
378 #endif
379
380 const long nRemaining =
381 - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
382 if ( nRemaining > 0 && !GetUpper()->IsSctFrm() &&
383 nRemaining != ( bVert ?
384 nMyPos - Frm().Right() :
385 Frm().Top() - nMyPos ) )
386 {
387 UNDO_SWAP( this )
388 return sal_True;
389 }
390 }
391
392 UNDO_SWAP( this )
393
394 return sal_False;
395 }
396
397 /*************************************************************************
398 * SwTxtFrm::AdjustFrm()
399 *************************************************************************/
400
AdjustFrm(const SwTwips nChgHght,sal_Bool bHasToFit)401 void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
402 {
403 if( IsUndersized() )
404 {
405 if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized)
406 return;
407 SetUndersized( nChgHght == 0 || bHasToFit );
408 }
409
410 // AdjustFrm is called with a swapped frame during
411 // formatting but the frame is not swapped during FormatEmpty
412 SWAP_IF_SWAPPED( this )
413 SWRECTFN ( this )
414
415 // Die Size-Variable des Frames wird durch Grow inkrementiert
416 // oder durch Shrink dekrementiert. Wenn die Groesse
417 // unveraendert ist, soll nichts passieren!
418 if( nChgHght >= 0)
419 {
420 SwTwips nChgHeight = nChgHght;
421 if( nChgHght && !bHasToFit )
422 {
423 if( IsInFtn() && !IsInSct() )
424 {
425 SwTwips nReal = Grow( nChgHght, sal_True );
426 if( nReal < nChgHght )
427 {
428 SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
429 nChgHght - nReal );
430 SwFrm* pCont = FindFtnFrm()->GetUpper();
431
432 if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
433 {
434 (Frm().*fnRect->fnAddBottom)( nChgHght );
435 if( bVert )
436 Prt().SSize().Width() += nChgHght;
437 else
438 Prt().SSize().Height() += nChgHght;
439 UNDO_SWAP( this )
440 return;
441 }
442 }
443 }
444
445 Grow( nChgHght );
446
447 if ( IsInFly() )
448 {
449 //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es
450 //sehr wahrscheinlich, dass dieser Fly durch das Grow seine
451 //Position veraendert - also muss auch meine Position korrigiert
452 //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig).
453 //Die Vorgaenger muessen berechnet werden, damit die Position
454 //korrekt berechnet werden kann.
455 if ( GetPrev() )
456 {
457 SwFrm *pPre = GetUpper()->Lower();
458 do
459 { pPre->Calc();
460 pPre = pPre->GetNext();
461 } while ( pPre && pPre != this );
462 }
463 const Point aOldPos( Frm().Pos() );
464 MakePos();
465 if ( aOldPos != Frm().Pos() )
466 {
467 // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
468 // No format is performed for the floating screen objects.
469 InvalidateObjs( true );
470 }
471 }
472 nChgHeight = 0;
473 }
474 // Ein Grow() wird von der Layout-Seite immer akzeptiert,
475 // also auch, wenn die FixSize des umgebenden Layoutframes
476 // dies nicht zulassen sollte. Wir ueberpruefen diesen
477 // Fall und korrigieren die Werte.
478 // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht
479 // weiter geschrumpft werden als es seine Groesse zulaesst.
480 SwTwips nRstHeight;
481 if ( IsVertical() )
482 {
483 ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
484
485 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
486 if ( IsVertLR() )
487 nRstHeight = GetUpper()->Frm().Left()
488 + GetUpper()->Prt().Left()
489 + GetUpper()->Prt().Width()
490 - Frm().Left();
491 else
492 nRstHeight = Frm().Left() + Frm().Width() -
493 ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
494 }
495 else
496 nRstHeight = GetUpper()->Frm().Top()
497 + GetUpper()->Prt().Top()
498 + GetUpper()->Prt().Height()
499 - Frm().Top();
500
501 //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil
502 //durch eine vertikale Ausrichtung auch oben noch Raum sein kann.
503 // --> OD 2004-11-25 #115759# - assure, that first lower in upper
504 // is the current one or is valid.
505 if ( IsInTab() &&
506 ( GetUpper()->Lower() == this ||
507 GetUpper()->Lower()->IsValid() ) )
508 // <--
509 {
510 long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
511 (GetUpper()->*fnRect->fnGetPrtTop)() );
512 ASSERT( nAdd >= 0, "Ey" );
513 nRstHeight += nAdd;
514 }
515
516 /* ------------------------------------
517 * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines
518 * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der
519 * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der
520 * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur
521 * Endlosschleife.
522 * -----------------------------------*/
523 SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
524 SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
525
526 if( nRstHeight < nFrmHeight )
527 {
528 //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu
529 //klein ist und der Upper noch Platz schaffen kann.
530 if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
531 nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
532 // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit
533 // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen
534 // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige
535 // Spaltengroesse ermitteln kann.
536 if ( nRstHeight < nFrmHeight )
537 {
538 if( bHasToFit || !IsMoveable() ||
539 ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
540 {
541 SetUndersized( sal_True );
542 Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
543 }
544 else
545 SetUndersized( sal_False );
546 }
547 }
548 else if( nChgHeight )
549 {
550 if( nRstHeight - nFrmHeight < nChgHeight )
551 nChgHeight = nRstHeight - nFrmHeight;
552 if( nChgHeight )
553 Grow( nChgHeight );
554 }
555 }
556 else
557 Shrink( -nChgHght );
558
559 UNDO_SWAP( this )
560 }
561
GetTabStopInfo(SwTwips CurrentPos)562 com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > SwTxtFrm::GetTabStopInfo( SwTwips CurrentPos )
563 {
564 com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > tabs(1);
565 ::com::sun::star::style::TabStop ts;
566
567 SwTxtFormatInfo aInf( this );
568 SwTxtFormatter aLine( this, &aInf );
569 SwTxtCursor TxtCursor( this, &aInf );
570 const Point aCharPos( TxtCursor.GetTopLeft() );
571
572
573 SwTwips nRight = aLine.Right();
574 CurrentPos -= aCharPos.X();
575
576 // get current tab stop information stored in the Frm
577 const SvxTabStop *pTS = aLine.GetLineInfo().GetTabStop( CurrentPos, nRight );
578
579 if( !pTS )
580 {
581 return com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop >();
582 }
583
584 // copy tab stop information into a Sequence, which only contains one element.
585 ts.Position = pTS->GetTabPos();
586 ts.DecimalChar = pTS->GetDecimal();
587 ts.FillChar = pTS->GetFill();
588 switch( pTS->GetAdjustment() )
589 {
590 case SVX_TAB_ADJUST_LEFT : ts.Alignment = ::com::sun::star::style::TabAlign_LEFT; break;
591 case SVX_TAB_ADJUST_CENTER : ts.Alignment = ::com::sun::star::style::TabAlign_CENTER; break;
592 case SVX_TAB_ADJUST_RIGHT : ts.Alignment = ::com::sun::star::style::TabAlign_RIGHT; break;
593 case SVX_TAB_ADJUST_DECIMAL: ts.Alignment = ::com::sun::star::style::TabAlign_DECIMAL; break;
594 case SVX_TAB_ADJUST_DEFAULT: ts.Alignment = ::com::sun::star::style::TabAlign_DEFAULT; break;
595 default: break; // prevent warning
596 }
597
598 tabs[0] = ts;
599 return tabs;
600 }
601 /*************************************************************************
602 * SwTxtFrm::AdjustFollow()
603 *************************************************************************/
604
605 /* AdjustFollow erwartet folgende Situation:
606 * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird
607 * im Follow eingestellt.
608 * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst
609 * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht.
610 */
611
_AdjustFollow(SwTxtFormatter & rLine,const xub_StrLen nOffset,const xub_StrLen nEnd,const sal_uInt8 nMode)612 void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
613 const xub_StrLen nOffset, const xub_StrLen nEnd,
614 const sal_uInt8 nMode )
615 {
616 SwFrmSwapper aSwapper( this, sal_False );
617
618 // Wir haben den Rest der Textmasse: alle Follows loeschen
619 // Sonderfall sind DummyPortions()
620 // - special cases are controlled by parameter <nMode>.
621 if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
622 {
623 while( GetFollow() )
624 {
625 if( ((SwTxtFrm*)GetFollow())->IsLocked() )
626 {
627 ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." );
628 return;
629 }
630 JoinFrm();
631 }
632
633 return;
634 }
635
636 // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal
637 // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich
638 // kann sich dadurch auch der Offset verschieben:
639 const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
640 rLine.FormatQuoVadis(nOffset) : nOffset;
641
642 if( !(nMode & 1) )
643 {
644 // Wir klauen unseren Follows Textmasse, dabei kann es passieren,
645 // dass wir einige Follows Joinen muessen.
646 while( GetFollow() && GetFollow()->GetFollow() &&
647 nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
648 {
649 DBG_LOOP;
650 JoinFrm();
651 }
652 }
653
654 // Der Ofst hat sich verschoben.
655 if( GetFollow() )
656 {
657 #if OSL_DEBUG_LEVEL > 1
658 static sal_Bool bTest = sal_False;
659 if( !bTest || ( nMode & 1 ) )
660 #endif
661 if ( nMode )
662 GetFollow()->ManipOfst( 0 );
663
664 if ( CalcFollow( nNewOfst ) ) // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst
665 rLine.SetOnceMore( sal_True );
666 }
667 }
668
669 /*************************************************************************
670 * SwTxtFrm::JoinFrm()
671 *************************************************************************/
672
JoinFrm()673 SwCntntFrm *SwTxtFrm::JoinFrm()
674 {
675 ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
676 SwTxtFrm *pFoll = GetFollow();
677
678 SwTxtFrm *pNxt = pFoll->GetFollow();
679
680 // Alle Fussnoten des zu zerstoerenden Follows werden auf uns
681 // umgehaengt.
682 xub_StrLen nStart = pFoll->GetOfst();
683 if ( pFoll->HasFtn() )
684 {
685 const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
686 if( pHints )
687 {
688 SwFtnBossFrm *pFtnBoss = 0;
689 SwFtnBossFrm *pEndBoss = 0;
690 for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
691 {
692 const SwTxtAttr *pHt = (*pHints)[i];
693 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
694 {
695 if( pHt->GetFtn().IsEndNote() )
696 {
697 if( !pEndBoss )
698 pEndBoss = pFoll->FindFtnBossFrm();
699 pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
700 }
701 else
702 {
703 if( !pFtnBoss )
704 pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
705 pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
706 }
707 SetFtn( sal_True );
708 }
709 }
710 }
711 }
712
713 #ifdef DBG_UTIL
714 else if ( pFoll->GetValidPrtAreaFlag() ||
715 pFoll->GetValidSizeFlag() )
716 {
717 pFoll->CalcFtnFlag();
718 ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." );
719 }
720 #endif
721
722 pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
723 pFoll->SetFtn( sal_False );
724 // --> OD 2005-12-01 #i27138#
725 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
726 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
727 // and relation CONTENT_FLOWS_TO for current previous paragraph, which
728 // is <this>, will change.
729 {
730 ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() );
731 if ( pViewShell && pViewShell->GetLayout() &&
732 pViewShell->GetLayout()->IsAnyShellAccessible() )
733 {
734 pViewShell->InvalidateAccessibleParaFlowRelation(
735 dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
736 this );
737 }
738 }
739 // <--
740 pFoll->Cut();
741 delete pFoll;
742 pFollow = pNxt;
743 return pNxt;
744 }
745
746 /*************************************************************************
747 * SwTxtFrm::SplitFrm()
748 *************************************************************************/
749
SplitFrm(const xub_StrLen nTxtPos)750 SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
751 {
752 SWAP_IF_SWAPPED( this )
753
754 // Durch das Paste wird ein Modify() an mich verschickt.
755 // Damit meine Daten nicht verschwinden, locke ich mich.
756 SwTxtFrmLocker aLock( this );
757 SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this ));
758 pNew->bIsFollow = sal_True;
759
760 pNew->SetFollow( GetFollow() );
761 SetFollow( pNew );
762
763 pNew->Paste( GetUpper(), GetNext() );
764 // --> OD 2005-12-01 #i27138#
765 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
766 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
767 // and relation CONTENT_FLOWS_TO for current previous paragraph, which
768 // is <this>, will change.
769 {
770 ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
771 if ( pViewShell && pViewShell->GetLayout() &&
772 pViewShell->GetLayout()->IsAnyShellAccessible() )
773 {
774 pViewShell->InvalidateAccessibleParaFlowRelation(
775 dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
776 this );
777 }
778 }
779 // <--
780
781 // Wenn durch unsere Aktionen Fussnoten in pNew landen,
782 // so muessen sie umgemeldet werden.
783 if ( HasFtn() )
784 {
785 const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
786 if( pHints )
787 {
788 SwFtnBossFrm *pFtnBoss = 0;
789 SwFtnBossFrm *pEndBoss = 0;
790 for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
791 {
792 const SwTxtAttr *pHt = (*pHints)[i];
793 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
794 {
795 if( pHt->GetFtn().IsEndNote() )
796 {
797 if( !pEndBoss )
798 pEndBoss = FindFtnBossFrm();
799 pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
800 }
801 else
802 {
803 if( !pFtnBoss )
804 pFtnBoss = FindFtnBossFrm( sal_True );
805 pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
806 }
807 pNew->SetFtn( sal_True );
808 }
809 }
810 }
811 }
812
813 #ifdef DBG_UTIL
814 else
815 {
816 CalcFtnFlag( nTxtPos-1 );
817 ASSERT( !HasFtn(), "Missing FtnFlag." );
818 }
819 #endif
820
821 MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );
822
823 // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt.
824
825 pNew->ManipOfst( nTxtPos );
826
827 UNDO_SWAP( this )
828 return pNew;
829 }
830
831
832 /*************************************************************************
833 * virtual SwTxtFrm::SetOfst()
834 *************************************************************************/
835
_SetOfst(const xub_StrLen nNewOfst)836 void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
837 {
838 #ifdef DBGTXT
839 // Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0)
840 // zulaessig ist: bug 3496
841 ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." );
842 #endif
843
844 // Die Invalidierung unseres Follows ist nicht noetig.
845 // Wir sind ein Follow, werden gleich formatiert und
846 // rufen von dort aus das SetOfst() !
847 nOfst = nNewOfst;
848 SwParaPortion *pPara = GetPara();
849 if( pPara )
850 {
851 SwCharRange &rReformat = *(pPara->GetReformat());
852 rReformat.Start() = 0;
853 rReformat.Len() = GetTxt().Len();
854 *(pPara->GetDelta()) = rReformat.Len();
855 }
856 InvalidateSize();
857 }
858
859 /*************************************************************************
860 * SwTxtFrm::CalcPreps
861 *************************************************************************/
862
CalcPreps()863 sal_Bool SwTxtFrm::CalcPreps()
864 {
865 ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
866 SWRECTFN( this );
867
868 SwParaPortion *pPara = GetPara();
869 if ( !pPara )
870 return sal_False;
871 sal_Bool bPrep = pPara->IsPrep();
872 sal_Bool bPrepWidows = pPara->IsPrepWidows();
873 sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
874 sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
875 ResetPreps();
876
877 sal_Bool bRet = sal_False;
878 if( bPrep && !pPara->GetReformat()->Len() )
879 {
880 // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel
881 // zuschlug.
882 // Es kann in unguenstigen Faellen vorkommen, dass auch ein
883 // PrepAdjust vorliegt (3680)!
884 if( bPrepWidows )
885 {
886 if( !GetFollow() )
887 {
888 ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
889 return sal_False;
890 }
891
892 // Wir muessen uns auf zwei Faelle einstellen:
893 // Wir konnten dem Follow noch ein paar Zeilen abgeben,
894 // -> dann muessen wir schrumpfen
895 // oder wir muessen auf die naechste Seite
896 // -> dann lassen wir unseren Frame zu gross werden.
897
898 SwTwips nChgHeight = GetParHeight();
899 if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
900 {
901 if( bPrepMustFit )
902 {
903 GetFollow()->SetJustWidow( sal_True );
904 GetFollow()->Prepare( PREP_CLEAR );
905 }
906 else if ( bVert )
907 {
908 Frm().Width( Frm().Width() + Frm().Left() );
909 Prt().Width( Prt().Width() + Frm().Left() );
910 Frm().Left( 0 );
911 SetWidow( sal_True );
912 }
913 else
914 {
915 SwTwips nTmp = LONG_MAX - (Frm().Top()+10000);
916 SwTwips nDiff = nTmp - Frm().Height();
917 Frm().Height( nTmp );
918 Prt().Height( Prt().Height() + nDiff );
919 SetWidow( sal_True );
920 }
921 }
922 else
923 {
924 ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
925 "+SwTxtFrm::CalcPrep: wanna shrink" );
926
927 nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;
928
929 GetFollow()->SetJustWidow( sal_True );
930 GetFollow()->Prepare( PREP_CLEAR );
931 Shrink( nChgHeight );
932 SwRect &rRepaint = *(pPara->GetRepaint());
933
934 if ( bVert )
935 {
936 SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
937 SwitchVerticalToHorizontal( aRepaint );
938 rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
939 }
940 else
941 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
942
943 // 6792: Rrand < LRand und Repaint
944 if( 0 >= rRepaint.Width() )
945 rRepaint.Width(1);
946 }
947 bRet = sal_True;
948 }
949
950 else if ( bPrepAdjust )
951 {
952 if ( HasFtn() )
953 {
954 if( !CalcPrepFtnAdjust() )
955 {
956 if( bPrepMustFit )
957 {
958 SwTxtLineAccess aAccess( this );
959 aAccess.GetPara()->SetPrepMustFit( sal_True );
960 }
961 return sal_False;
962 }
963 }
964
965 SWAP_IF_NOT_SWAPPED( this )
966
967 SwTxtFormatInfo aInf( this );
968 SwTxtFormatter aLine( this, &aInf );
969
970 WidowsAndOrphans aFrmBreak( this );
971 // Egal was die Attribute meinen, bei MustFit wird
972 // der Absatz im Notfall trotzdem gesplittet...
973 if( bPrepMustFit )
974 {
975 aFrmBreak.SetKeep( sal_False );
976 aFrmBreak.ClrOrphLines();
977 }
978 // Bevor wir FormatAdjust aufrufen muessen wir dafuer
979 // sorgen, dass die Zeilen, die unten raushaengen
980 // auch tatsaechlich abgeschnitten werden.
981 // OD 2004-02-25 #i16128# - method renamed
982 sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
983 bRet = sal_True;
984 while( !bBreak && aLine.Next() )
985 {
986 // OD 2004-02-25 #i16128# - method renamed
987 bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
988 }
989 if( bBreak )
990 {
991 // Es gibt Komplikationen: wenn TruncLines gerufen wird,
992 // veraendern sich ploetzlich die Bedingungen in
993 // IsInside, so dass IsBreakNow andere Ergebnisse
994 // liefern kann. Aus diesem Grund wird rFrmBreak bekannt
995 // gegeben, dass da wo rLine steht, das Ende erreicht
996 // ist. Mal sehen, ob's klappt ...
997 aLine.TruncLines();
998 aFrmBreak.SetRstHeight( aLine );
999 FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
1000 }
1001 else
1002 {
1003 if( !GetFollow() )
1004 {
1005 FormatAdjust( aLine, aFrmBreak,
1006 aInf.GetTxt().Len(), aInf.IsStop() );
1007 }
1008 else if ( !aFrmBreak.IsKeepAlways() )
1009 {
1010 // Siehe Bug: 2320
1011 // Vor dem Master wird eine Zeile geloescht, der Follow
1012 // koennte eine Zeile abgeben.
1013 const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
1014 *(pPara->GetReformat()) += aFollowRg;
1015 // Es soll weitergehen!
1016 bRet = sal_False;
1017 }
1018 }
1019
1020 UNDO_SWAP( this )
1021 // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts
1022 // brachte, muessen wir amputieren.
1023 if( bPrepMustFit )
1024 {
1025 const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
1026 const SwTwips nIs = (Frm().*fnRect->fnGetBottom)();
1027
1028 if( bVert && nIs < nMust )
1029 {
1030 Shrink( nMust - nIs );
1031 if( Prt().Width() < 0 )
1032 Prt().Width( 0 );
1033 SetUndersized( sal_True );
1034 }
1035 else if ( ! bVert && nIs > nMust )
1036 {
1037 Shrink( nIs - nMust );
1038 if( Prt().Height() < 0 )
1039 Prt().Height( 0 );
1040 SetUndersized( sal_True );
1041 }
1042 }
1043 }
1044 }
1045 pPara->SetPrepMustFit( bPrepMustFit );
1046 return bRet;
1047 }
1048
1049
1050 /*************************************************************************
1051 * SwTxtFrm::FormatAdjust()
1052 *************************************************************************/
1053
1054 // Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt
1055 #define CHG_OFFSET( pFrm, nNew )\
1056 {\
1057 if( pFrm->GetOfst() < nNew )\
1058 pFrm->MoveFlyInCnt( this, 0, nNew );\
1059 else if( pFrm->GetOfst() > nNew )\
1060 MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
1061 }
1062
FormatAdjust(SwTxtFormatter & rLine,WidowsAndOrphans & rFrmBreak,const xub_StrLen nStrLen,const sal_Bool bDummy)1063 void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
1064 WidowsAndOrphans &rFrmBreak,
1065 const xub_StrLen nStrLen,
1066 const sal_Bool bDummy )
1067 {
1068 SWAP_IF_NOT_SWAPPED( this )
1069
1070 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1071
1072 xub_StrLen nEnd = rLine.GetStart();
1073
1074 sal_Bool bHasToFit = pPara->IsPrepMustFit();
1075
1076 // Das StopFlag wird durch Fussnoten gesetzt,
1077 // die auf die naechste Seite wollen.
1078 // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)>
1079 // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
1080 // even if due to widow rule no enough lines exists.
1081 sal_uInt8 nNew = ( !GetFollow() &&
1082 nEnd < nStrLen &&
1083 ( rLine.IsStop() ||
1084 ( bHasToFit
1085 ? ( rLine.GetLineNr() > 1 &&
1086 !rFrmBreak.IsInside( rLine ) )
1087 : rFrmBreak.IsBreakNow( rLine ) ) ) )
1088 ? 1 : 0;
1089 // --> OD #i84870#
1090 // no split of text frame, which only contains a as-character anchored object
1091 const bool bOnlyContainsAsCharAnchoredObj =
1092 !IsFollow() && nStrLen == 1 &&
1093 GetDrawObjs() && GetDrawObjs()->Count() == 1 &&
1094 (*GetDrawObjs())[0]->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR;
1095 if ( nNew && bOnlyContainsAsCharAnchoredObj )
1096 {
1097 nNew = 0;
1098 }
1099 // <--
1100 if ( nNew )
1101 {
1102 SplitFrm( nEnd );
1103 }
1104
1105 const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());
1106
1107 const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
1108 pBodyFrm->Frm().Width() :
1109 pBodyFrm->Frm().Height() ) : 0;
1110
1111 // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass
1112 // sie jetzt gueltig sind.
1113 *(pPara->GetReformat()) = SwCharRange();
1114 sal_Bool bDelta = *pPara->GetDelta() != 0;
1115 *(pPara->GetDelta()) = 0;
1116
1117 if( rLine.IsStop() )
1118 {
1119 rLine.TruncLines( sal_True );
1120 nNew = 1;
1121 }
1122
1123 // FindBreak schneidet die letzte Zeile ab.
1124 if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
1125 {
1126 // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende
1127 // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt.
1128 // Ansonsten ist nEnd das Ende der letzten Zeile im Master.
1129 xub_StrLen nOld = nEnd;
1130 nEnd = rLine.GetEnd();
1131 if( GetFollow() )
1132 {
1133 if( nNew && nOld < nEnd )
1134 RemoveFtn( nOld, nEnd - nOld );
1135 CHG_OFFSET( GetFollow(), nEnd )
1136 if( !bDelta )
1137 GetFollow()->ManipOfst( nEnd );
1138 }
1139 }
1140 else
1141 { // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden,
1142 // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden.
1143 // Dies muss auch geschehen, wenn die Textmasse komplett im Master
1144 // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere
1145 // Zeile (ohne Textmassse) notwendig machen!
1146 nEnd = rLine.GetEnd();
1147 if( GetFollow() )
1148 {
1149 // OD 21.03.2003 #108121# - Another case for not joining the follow:
1150 // Text frame has no content, but a numbering. Then, do *not* join.
1151 // Example of this case: When an empty, but numbered paragraph
1152 // at the end of page is completely displaced by a fly frame.
1153 // Thus, the text frame introduced a follow by a
1154 // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
1155 // the numbering and must stay.
1156 if ( GetFollow()->GetOfst() != nEnd ||
1157 GetFollow()->IsFieldFollow() ||
1158 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
1159 {
1160 nNew |= 3;
1161 }
1162 CHG_OFFSET( GetFollow(), nEnd )
1163 GetFollow()->ManipOfst( nEnd );
1164 }
1165 else
1166 {
1167 // OD 21.03.2003 #108121# - Only split frame, if the frame contains
1168 // content or contains no content, but has a numbering.
1169 // OD #i84870# - no split, if text frame only contains one
1170 // as-character anchored object.
1171 if ( !bOnlyContainsAsCharAnchoredObj &&
1172 ( nStrLen > 0 ||
1173 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
1174 )
1175 {
1176 SplitFrm( nEnd );
1177 nNew |= 3;
1178 }
1179 }
1180 // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn()
1181 // dann muessen wir auffuellen, um Oszillationen zu vermeiden!
1182 if( bDummy && pBodyFrm &&
1183 nBodyHeight < ( IsVertical() ?
1184 pBodyFrm->Frm().Width() :
1185 pBodyFrm->Frm().Height() ) )
1186 rLine.MakeDummyLine();
1187 }
1188
1189 // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein,
1190 // in AdjustFollow() stellen wir unseren FolgeFrame ein.
1191
1192 const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
1193 const SwTwips nOldHeight = Prt().SSize().Height();
1194 SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
1195 // --> OD #i84870# - no shrink of text frame, if it only contains one
1196 // as-character anchored object.
1197 if ( nChg < 0 &&
1198 bOnlyContainsAsCharAnchoredObj )
1199 {
1200 nChg = 0;
1201 }
1202 // <--
1203
1204 // Vertical Formatting:
1205 // The (rotated) repaint rectangle's x coordinate referes to the frame.
1206 // If the frame grows (or shirks) the repaint rectangle cannot simply
1207 // be rotated back after formatting, because we use the upper left point
1208 // of the frame for rotation. This point changes when growing/shrinking.
1209
1210 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
1211 if ( IsVertical() && !IsVertLR() && nChg )
1212 {
1213 SwRect &rRepaint = *(pPara->GetRepaint());
1214 rRepaint.Left( rRepaint.Left() - nChg );
1215 rRepaint.Width( rRepaint.Width() - nChg );
1216 }
1217
1218 AdjustFrm( nChg, bHasToFit );
1219
1220 /*
1221 // FME 16.07.2003 #i16930# - removed this code because it did not
1222 // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the
1223 // next page, instead the print area was recalculated and
1224 // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ) invalidated
1225 // the other flags => loop
1226
1227 // OD 04.04.2003 #108446# - handle special case:
1228 // If text frame contains no content and just has split, because of a
1229 // line stop, it has to move forward. To force this forward move without
1230 // unnecessary formatting of its footnotes and its follow, especially in
1231 // columned sections, adjust frame height to zero (0) and do not perform
1232 // the intrinsic format of the follow.
1233 // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward.
1234 sal_Bool bForcedNoIntrinsicFollowCalc = sal_False;
1235 if ( nEnd == 0 &&
1236 rLine.IsStop() && HasFollow() && nNew == 1
1237 )
1238 {
1239 AdjustFrm( -Frm().SSize().Height(), bHasToFit );
1240 Prt().Pos().Y() = 0;
1241 Prt().Height( Frm().Height() );
1242 if ( FollowFormatAllowed() )
1243 {
1244 bForcedNoIntrinsicFollowCalc = sal_True;
1245 ForbidFollowFormat();
1246 }
1247 }
1248 else
1249 {
1250 AdjustFrm( nChg, bHasToFit );
1251 }
1252 */
1253
1254 if( HasFollow() || IsInFtn() )
1255 _AdjustFollow( rLine, nEnd, nStrLen, nNew );
1256
1257 // FME 16.07.2003 #i16930# - removed this code because it did not work
1258 // correctly
1259 // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above
1260 // special case has forbit it.
1261 /* if ( bForcedNoIntrinsicFollowCalc )
1262 {
1263 AllowFollowFormat();
1264 }
1265 */
1266
1267 pPara->SetPrepMustFit( sal_False );
1268
1269 UNDO_SWAP( this )
1270 }
1271
1272 /*************************************************************************
1273 * SwTxtFrm::FormatLine()
1274 *************************************************************************/
1275
1276 // bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde.
1277 // Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht.
1278
1279
FormatLine(SwTxtFormatter & rLine,const sal_Bool bPrev)1280 sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
1281 {
1282 ASSERT( ! IsVertical() || IsSwapped(),
1283 "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
1284 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1285 // Nach rLine.FormatLine() haelt nStart den neuen Wert,
1286 // waehrend in pOldStart der alte Offset gepflegt wird.
1287 // Ueber diesen Weg soll das nDelta ersetzt werden.
1288 // *pOldStart += rLine.GetCurr()->GetLen();
1289 const SwLineLayout *pOldCur = rLine.GetCurr();
1290 const xub_StrLen nOldLen = pOldCur->GetLen();
1291 const KSHORT nOldAscent = pOldCur->GetAscent();
1292 const KSHORT nOldHeight = pOldCur->Height();
1293 const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin();
1294 const sal_Bool bOldHyph = pOldCur->IsEndHyph();
1295 SwTwips nOldTop = 0;
1296 SwTwips nOldBottom = 0;
1297 if( rLine.GetCurr()->IsClipping() )
1298 rLine.CalcUnclipped( nOldTop, nOldBottom );
1299
1300 const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );
1301
1302 ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
1303 "SwTxtFrm::FormatLine: frame leaves orbit." );
1304 ASSERT( rLine.GetCurr()->Height(),
1305 "SwTxtFrm::FormatLine: line height is zero" );
1306
1307 // Das aktuelle Zeilenumbruchobjekt.
1308 const SwLineLayout *pNew = rLine.GetCurr();
1309
1310 sal_Bool bUnChg = nOldLen == pNew->GetLen() &&
1311 bOldHyph == pNew->IsEndHyph();
1312 if ( bUnChg && !bPrev )
1313 {
1314 // 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922
1315 const long nWidthDiff = nOldWidth > pNew->Width()
1316 ? nOldWidth - pNew->Width()
1317 : pNew->Width() - nOldWidth;
1318
1319 // we only declare a line as unchanged, if its main values have not
1320 // changed and it is not the last line (!paragraph end symbol!)
1321 bUnChg = nOldHeight == pNew->Height() &&
1322 nOldAscent == pNew->GetAscent() &&
1323 nWidthDiff <= SLOPPY_TWIPS &&
1324 pOldCur->GetNext();
1325 }
1326
1327 // rRepaint wird berechnet:
1328 const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
1329 SwRepaint &rRepaint = *(pPara->GetRepaint());
1330 if( bUnChg && rRepaint.Top() == rLine.Y()
1331 && (bPrev || nNewStart <= pPara->GetReformat()->Start())
1332 && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
1333 {
1334 rRepaint.Top( nBottom );
1335 rRepaint.Height( 0 );
1336 }
1337 else
1338 {
1339 if( nOldTop )
1340 {
1341 if( nOldTop < rRepaint.Top() )
1342 rRepaint.Top( nOldTop );
1343 if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
1344 {
1345 rRepaint.Bottom( nOldBottom - 1 );
1346 rLine.SetUnclipped( sal_True );
1347 }
1348 }
1349 if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
1350 {
1351 SwTwips nTmpTop, nTmpBottom;
1352 rLine.CalcUnclipped( nTmpTop, nTmpBottom );
1353 if( nTmpTop < rRepaint.Top() )
1354 rRepaint.Top( nTmpTop );
1355 if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
1356 {
1357 rRepaint.Bottom( nTmpBottom - 1 );
1358 rLine.SetUnclipped( sal_True );
1359 }
1360 }
1361 else
1362 {
1363 if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
1364 {
1365 rRepaint.Bottom( nBottom - 1 );
1366 rLine.SetUnclipped( sal_False );
1367 }
1368 }
1369 SwTwips nRght = Max( nOldWidth, pNew->Width() +
1370 pNew->GetHangingMargin() );
1371 ViewShell *pSh = getRootFrm()->GetCurrShell();
1372 const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
1373 if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
1374 nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
1375 else
1376 nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
1377 nRght += rLine.GetLeftMargin();
1378 if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
1379 rRepaint.SetRightOfst( nRght );
1380
1381 // Finally we enlarge the repaint rectangle if we found an underscore
1382 // within our line. 40 Twips should be enough
1383 const sal_Bool bHasUnderscore =
1384 ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
1385 if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
1386 rRepaint.Bottom( rRepaint.Bottom() + 40 );
1387
1388 ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
1389 }
1390 if( !bUnChg )
1391 rLine.SetChanges();
1392
1393 // Die gute, alte nDelta-Berechnung:
1394 *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);
1395
1396 // Stop!
1397 if( rLine.IsStop() )
1398 return sal_False;
1399
1400 // Unbedingt noch eine Zeile
1401 if( rLine.IsNewLine() )
1402 return sal_True;
1403
1404 // bis zum Ende des Strings ?
1405 if( nNewStart >= GetTxtNode()->GetTxt().Len() )
1406 return sal_False;
1407
1408 if( rLine.GetInfo().IsShift() )
1409 return sal_True;
1410
1411 // Ende des Reformats erreicht ?
1412 const xub_StrLen nEnd = pPara->GetReformat()->Start() +
1413 pPara->GetReformat()->Len();
1414
1415 if( nNewStart <= nEnd )
1416 return sal_True;
1417
1418 return 0 != *(pPara->GetDelta());
1419 }
1420
1421 /*************************************************************************
1422 * SwTxtFrm::_Format()
1423 *************************************************************************/
1424
_Format(SwTxtFormatter & rLine,SwTxtFormatInfo & rInf,const sal_Bool bAdjust)1425 void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
1426 const sal_Bool bAdjust )
1427 {
1428 ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );
1429
1430 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1431 rLine.SetUnclipped( sal_False );
1432
1433 // Das war dem C30 zu kompliziert: aString( GetTxt() );
1434 const XubString &rString = GetTxtNode()->GetTxt();
1435 const xub_StrLen nStrLen = rString.Len();
1436
1437 SwCharRange &rReformat = *(pPara->GetReformat());
1438 SwRepaint &rRepaint = *(pPara->GetRepaint());
1439 SwRepaint *pFreeze = NULL;
1440
1441 // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt.
1442 // Fuer diesen Fall wird rReformat angepasst.
1443 if( rReformat.Len() > nStrLen )
1444 rReformat.Len() = nStrLen;
1445
1446 // Optimiert:
1447 xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
1448 if( nEnd > nStrLen )
1449 {
1450 rReformat.Len() = nStrLen - rReformat.Start();
1451 nEnd = nStrLen;
1452 }
1453
1454 SwTwips nOldBottom;
1455 if( GetOfst() && !IsFollow() )
1456 {
1457 rLine.Bottom();
1458 nOldBottom = rLine.Y();
1459 rLine.Top();
1460 }
1461 else
1462 nOldBottom = 0;
1463 rLine.CharToLine( rReformat.Start() );
1464
1465 // Worte koennen durch Fortfall oder Einfuegen eines Space
1466 // auf die Zeile vor der editierten hinausgezogen werden,
1467 // deshalb muss diese ebenfalls formatiert werden.
1468 // Optimierung: Wenn rReformat erst hinter dem ersten Wort der
1469 // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen.
1470 // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung
1471 // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen!
1472
1473 // --> FME 2005-04-18 #i46560#
1474 // FME: Yes, consider this case: (word ) has to go to the next line
1475 // because ) is a forbidden character at the beginning of a line although
1476 // (word would still fit on the previous line. Adding text right in front
1477 // of ) would not trigger a reformatting of the previous line. Adding 1
1478 // to the result of FindBrk() does not solve the problem in all cases,
1479 // nevertheless it should be sufficient.
1480 // <--
1481 sal_Bool bPrev = rLine.GetPrev() &&
1482 ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
1483 // --> FME 2005-04-18 #i46560#
1484 + 1
1485 // <--
1486 >= rReformat.Start() ||
1487 rLine.GetCurr()->IsRest() );
1488 if( bPrev )
1489 {
1490 while( rLine.Prev() )
1491 if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
1492 {
1493 if( !rLine.GetStart() )
1494 rLine.Top(); // damit NumDone nicht durcheinander kommt
1495 break;
1496 }
1497 xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
1498 if( nNew )
1499 {
1500 --nNew;
1501 if( CH_BREAK == rString.GetChar( nNew ) )
1502 {
1503 ++nNew;
1504 rLine.Next();
1505 bPrev = sal_False;
1506 }
1507 }
1508 rReformat.Len() += rReformat.Start() - nNew;
1509 rReformat.Start() = nNew;
1510 }
1511
1512 rRepaint.SetOfst( 0 );
1513 rRepaint.SetRightOfst( 0 );
1514 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
1515 if( pPara->IsMargin() )
1516 rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
1517 rRepaint.Top( rLine.Y() );
1518 // 6792: Rrand < LRand und Repaint
1519 if( 0 >= rRepaint.Width() )
1520 rRepaint.Width(1);
1521 WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );
1522
1523 // rLine steht jetzt auf der ersten Zeile, die formatiert werden
1524 // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird.
1525 // Das ganze sieht verdreht aus, aber es muss sichergestellt werden,
1526 // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die
1527 // nicht mehr passt.
1528 sal_Bool bFirst = sal_True;
1529 sal_Bool bFormat = sal_True;
1530
1531 // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren.
1532 // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die
1533 // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse
1534 // verloren, weil der Ofst im Follow falsch eingestellt wird.
1535
1536 // OD 2004-02-25 #i16128# - method renamed
1537 sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
1538 && aFrmBreak.IsBreakNowWidAndOrp( rLine );
1539 if( bBreak )
1540 {
1541 sal_Bool bPrevDone = 0 != rLine.Prev();
1542 // OD 2004-02-25 #i16128# - method renamed
1543 while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
1544 bPrevDone = 0 != rLine.Prev();
1545 if( bPrevDone )
1546 {
1547 aFrmBreak.SetKeep( sal_False );
1548 rLine.Next();
1549 }
1550 rLine.TruncLines();
1551
1552 // auf Nummer sicher:
1553 // OD 2004-02-25 #i16128# - method renamed
1554 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
1555 ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
1556 }
1557
1558 /* Bedeutung der folgenden Flags:
1559 Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn
1560 eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist.
1561 Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine
1562 Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt
1563 umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph
1564 verboten war.
1565 Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine
1566 Trennstelle erhalten hat, vorher aber keine hatte,
1567 Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet.
1568 */
1569 sal_Bool bJumpEndHyph = sal_False,
1570 bWatchEndHyph = sal_False,
1571 bJumpMidHyph = sal_False,
1572 bWatchMidHyph = sal_False;
1573
1574 const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
1575 sal_Bool bMaxHyph = ( 0 !=
1576 ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
1577 if ( bMaxHyph )
1578 rLine.InitCntHyph();
1579
1580 if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
1581 {
1582 const SwLineLayout* pLine;
1583 {
1584 SwTxtFrm *pMaster = FindMaster();
1585 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
1586 if( !pMaster->HasPara() )
1587 pMaster->GetFormatted();
1588 SwTxtSizeInfo aInf( pMaster );
1589 SwTxtIter aMasterLine( pMaster, &aInf );
1590 aMasterLine.Bottom();
1591 pLine = aMasterLine.GetCurr();
1592 }
1593 SwLinePortion* pRest =
1594 rLine.MakeRestPortion( pLine, GetOfst() );
1595 if( pRest )
1596 rInf.SetRest( pRest );
1597 else
1598 SetFieldFollow( sal_False );
1599 }
1600
1601 /* Zum Abbruchkriterium:
1602 * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt,
1603 * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow
1604 * wieder entfernt.
1605 * Eine weitere Komplikation: wenn wir der Master sind, so muessen
1606 * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile
1607 * vom Follow in den Master rutschen kann.
1608 */
1609 do
1610 {
1611 DBG_LOOP;
1612 if( bFirst )
1613 bFirst = sal_False;
1614 else
1615 {
1616 if ( bMaxHyph )
1617 {
1618 if ( rLine.GetCurr()->IsEndHyph() )
1619 rLine.CntEndHyph()++;
1620 else
1621 rLine.CntEndHyph() = 0;
1622 if ( rLine.GetCurr()->IsMidHyph() )
1623 rLine.CntMidHyph()++;
1624 else
1625 rLine.CntMidHyph() = 0;
1626 }
1627 if( !rLine.Next() )
1628 {
1629 if( !bFormat )
1630 {
1631 SwLinePortion* pRest =
1632 rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() );
1633 if( pRest )
1634 rInf.SetRest( pRest );
1635 }
1636 rLine.Insert( new SwLineLayout() );
1637 rLine.Next();
1638 bFormat = sal_True;
1639 }
1640 }
1641 if ( !bFormat && bMaxHyph &&
1642 (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
1643 {
1644 if ( rLine.GetCurr()->IsEndHyph() )
1645 {
1646 if ( bWatchEndHyph )
1647 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1648 }
1649 else
1650 {
1651 bFormat = bJumpEndHyph;
1652 bWatchEndHyph = sal_False;
1653 bJumpEndHyph = sal_False;
1654 }
1655 if ( rLine.GetCurr()->IsMidHyph() )
1656 {
1657 if ( bWatchMidHyph && !bFormat )
1658 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1659 }
1660 else
1661 {
1662 bFormat = bFormat || bJumpMidHyph;
1663 bWatchMidHyph = sal_False;
1664 bJumpMidHyph = sal_False;
1665 }
1666 }
1667 if( bFormat )
1668 {
1669 sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
1670 sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
1671 bFormat = FormatLine( rLine, bPrev );
1672 //9334: Es kann nur ein bPrev geben... (???)
1673 bPrev = sal_False;
1674 if ( bMaxHyph )
1675 {
1676 if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
1677 {
1678 bWatchEndHyph = !bOldEndHyph;
1679 bJumpEndHyph = bOldEndHyph;
1680 }
1681 if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
1682 {
1683 bWatchMidHyph = !bOldMidHyph;
1684 bJumpMidHyph = bOldMidHyph;
1685 }
1686 }
1687 }
1688
1689 if( !rInf.IsNewLine() )
1690 {
1691 if( !bFormat )
1692 bFormat = 0 != rInf.GetRest();
1693 if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
1694 break;
1695 if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
1696 !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
1697 {
1698 if( GetFollow() )
1699 {
1700 while( rLine.Next() )
1701 ; //Nothing
1702 pFreeze = new SwRepaint( rRepaint ); // to minimize painting
1703 }
1704 else
1705 break;
1706 }
1707 }
1708 // OD 2004-02-25 #i16128# - method renamed
1709 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
1710 }while( !bBreak );
1711
1712 if( pFreeze )
1713 {
1714 rRepaint = *pFreeze;
1715 delete pFreeze;
1716 }
1717
1718 if( !rLine.IsStop() )
1719 {
1720 // Wurde aller Text formatiert und gibt es noch weitere
1721 // Zeilenobjekte, dann sind diese jetzt ueberfluessig,
1722 // weil der Text kuerzer geworden ist.
1723 if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
1724 rLine.GetCurr()->GetNext() )
1725 {
1726 rLine.TruncLines();
1727 rLine.SetTruncLines( sal_True );
1728 }
1729 }
1730
1731 if( !rInf.IsTest() )
1732 {
1733 // Bei OnceMore lohnt sich kein FormatAdjust
1734 if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
1735 {
1736 FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
1737 }
1738 if( rRepaint.HasArea() )
1739 SetRepaint();
1740 rLine.SetTruncLines( sal_False );
1741 if( nOldBottom ) // Bei "gescollten" Absaetzen wird
1742 { // noch ueberprueft, ob durch Schrumpfen
1743 rLine.Bottom(); // das Scrolling ueberfluessig wurde.
1744 SwTwips nNewBottom = rLine.Y();
1745 if( nNewBottom < nOldBottom )
1746 _SetOfst( 0 );
1747 }
1748 }
1749 }
1750
1751 /*************************************************************************
1752 * SwTxtFrm::Format()
1753 *************************************************************************/
1754
FormatOnceMore(SwTxtFormatter & rLine,SwTxtFormatInfo & rInf)1755 void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
1756 {
1757 ASSERT( ! IsVertical() || IsSwapped(),
1758 "A frame is not swapped in SwTxtFrm::FormatOnceMore" );
1759
1760 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1761 if( !pPara )
1762 return;
1763
1764 // ggf gegen pPara
1765 KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight();
1766 sal_Bool bShrink = sal_False,
1767 bGrow = sal_False,
1768 bGoOn = rLine.IsOnceMore();
1769 sal_uInt8 nGo = 0;
1770 while( bGoOn )
1771 {
1772 #ifdef DBGTXT
1773 aDbstream << "OnceMore!" << endl;
1774 #endif
1775 ++nGo;
1776 rInf.Init();
1777 rLine.Top();
1778 if( !rLine.GetDropFmt() )
1779 rLine.SetOnceMore( sal_False );
1780 SwCharRange aRange( 0, rInf.GetTxt().Len() );
1781 *(pPara->GetReformat()) = aRange;
1782 _Format( rLine, rInf );
1783
1784 bGoOn = rLine.IsOnceMore();
1785 if( bGoOn )
1786 {
1787 const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
1788 if( nOld == nNew )
1789 bGoOn = sal_False;
1790 else
1791 {
1792 if( nOld > nNew )
1793 bShrink = sal_True;
1794 else
1795 bGrow = sal_True;
1796
1797 if( bShrink == bGrow || 5 < nGo )
1798 bGoOn = sal_False;
1799
1800 nOld = nNew;
1801 }
1802
1803 // 6107: Wenn was schief ging, muss noch einmal formatiert werden.
1804 if( !bGoOn )
1805 {
1806 rInf.CtorInitTxtFormatInfo( this );
1807 rLine.CtorInitTxtFormatter( this, &rInf );
1808 rLine.SetDropLines( 1 );
1809 rLine.CalcDropHeight( 1 );
1810 SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
1811 *(pPara->GetReformat()) = aTmpRange;
1812 _Format( rLine, rInf, sal_True );
1813 // 8047: Wir painten alles...
1814 SetCompletePaint();
1815 }
1816 }
1817 }
1818 }
1819
1820 /*************************************************************************
1821 * SwTxtFrm::_Format()
1822 *************************************************************************/
1823
1824
_Format(SwParaPortion * pPara)1825 void SwTxtFrm::_Format( SwParaPortion *pPara )
1826 {
1827 const xub_StrLen nStrLen = GetTxt().Len();
1828
1829 // AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten
1830 // Formatieren und Repainten zu fuehren???
1831 // if ( !(*pPara->GetDelta()) )
1832 // *(pPara->GetDelta()) = nStrLen;
1833 // else
1834 if ( !nStrLen )
1835 {
1836 // Leere Zeilen werden nicht lange gequaelt:
1837 // pPara wird blank geputzt
1838 // entspricht *pPara = SwParaPortion;
1839 sal_Bool bMustFit = pPara->IsPrepMustFit();
1840 pPara->Truncate();
1841 pPara->FormatReset();
1842 if( pBlink && pPara->IsBlinking() )
1843 pBlink->Delete( pPara );
1844
1845 // delete pSpaceAdd und pKanaComp
1846 pPara->FinishSpaceAdd();
1847 pPara->FinishKanaComp();
1848 pPara->ResetFlags();
1849 pPara->SetPrepMustFit( bMustFit );
1850 }
1851
1852 ASSERT( ! IsSwapped(), "A frame is swapped before _Format" );
1853
1854 if ( IsVertical() )
1855 SwapWidthAndHeight();
1856
1857 SwTxtFormatInfo aInf( this );
1858 SwTxtFormatter aLine( this, &aInf );
1859
1860 // OD 2004-01-15 #110582#
1861 HideAndShowObjects();
1862
1863 _Format( aLine, aInf );
1864
1865 if( aLine.IsOnceMore() )
1866 FormatOnceMore( aLine, aInf );
1867
1868 if ( IsVertical() )
1869 SwapWidthAndHeight();
1870
1871 ASSERT( ! IsSwapped(), "A frame is swapped after _Format" );
1872
1873 if( 1 < aLine.GetDropLines() )
1874 {
1875 if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
1876 SVX_ADJUST_BLOCK != aLine.GetAdjust() )
1877 {
1878 aLine.CalcDropAdjust();
1879 aLine.SetPaintDrop( sal_True );
1880 }
1881
1882 if( aLine.IsPaintDrop() )
1883 {
1884 aLine.CalcDropRepaint();
1885 aLine.SetPaintDrop( sal_False );
1886 }
1887 }
1888 }
1889
1890 /*************************************************************************
1891 * SwTxtFrm::Format()
1892 *************************************************************************/
1893
1894 /*
1895 * Format berechnet die Groesse des Textframes und ruft, wenn
1896 * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem
1897 * evtl. veraenderten Platzbedarf anzupassen.
1898 */
1899
Format(const SwBorderAttrs *)1900 void SwTxtFrm::Format( const SwBorderAttrs * )
1901 {
1902 DBG_LOOP;
1903 #if OSL_DEBUG_LEVEL > 1
1904 const XubString aXXX = GetTxtNode()->GetTxt();
1905 const SwTwips nDbgY = Frm().Top();
1906 (void)nDbgY;
1907 const SwPageFrm *pDbgPage = FindPageFrm();
1908 const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum();
1909 (void)nDbgPageNr;
1910 // Um zu gucken, ob es einen Ftn-Bereich gibt.
1911 const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont());
1912 (void)pDbgFtnCont;
1913
1914 #ifdef DBG_UTIL
1915 // nStopAt laesst sich vom CV bearbeiten.
1916 static MSHORT nStopAt = 0;
1917 if( nStopAt == GetFrmId() )
1918 {
1919 int i = GetFrmId();
1920 (void)i;
1921 }
1922 #endif
1923 #endif
1924
1925 #ifdef DEBUG_FTN
1926 //Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen.
1927 if( IsInFtn() )
1928 {
1929 const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper();
1930 const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm();
1931 const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum();
1932 if( !IsLocked() )
1933 {
1934 if( nFtnPageNr > nDbgPageNr )
1935 {
1936 SwTxtFrmLocker aLock(this);
1937 ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." );
1938 MSHORT i = 0;
1939 }
1940 }
1941 }
1942 #endif
1943
1944 SWRECTFN( this )
1945
1946 // --> OD 2008-01-31 #newlistlevelattrs#
1947 CalcAdditionalFirstLineOffset();
1948 // <--
1949
1950 // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen
1951 // gelegentlich TxtFrms mit einer Breite <=0.
1952 if( (Prt().*fnRect->fnGetWidth)() <= 0 )
1953 {
1954 // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante
1955 // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse
1956 // von 12 Pt. ein (240 Twip).
1957 SwTxtLineAccess aAccess( this );
1958 long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1959 if( aAccess.GetPara()->IsPrepMustFit() )
1960 {
1961 const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
1962 const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
1963 if( nDiff > 0 )
1964 Shrink( nDiff );
1965 }
1966 else if( 240 < nFrmHeight )
1967 Shrink( nFrmHeight - 240 );
1968 else if( 240 > nFrmHeight )
1969 Grow( 240 - nFrmHeight );
1970 nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1971
1972 long nTop = (this->*fnRect->fnGetTopMargin)();
1973 if( nTop > nFrmHeight )
1974 (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
1975 else if( (Prt().*fnRect->fnGetHeight)() < 0 )
1976 (Prt().*fnRect->fnSetHeight)( 0 );
1977 return;
1978 }
1979
1980 const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
1981 if ( nStrLen || !FormatEmpty() )
1982 {
1983
1984 SetEmpty( sal_False );
1985 // Um nicht durch verschachtelte Formats irritiert zu werden.
1986 FormatLevel aLevel;
1987 if( 12 == aLevel.GetLevel() )
1988 return;
1989
1990 // Die Formatinformationen duerfen u.U. nicht veraendert werden.
1991 if( IsLocked() )
1992 return;
1993
1994 // 8708: Vorsicht, das Format() kann auch durch GetFormatted()
1995 // angestossen werden.
1996 if( IsHiddenNow() )
1997 {
1998 long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
1999 if( nPrtHeight )
2000 {
2001 HideHidden();
2002 Shrink( nPrtHeight );
2003 }
2004 else
2005 {
2006 // OD 2004-01-20 #110582# - assure that objects anchored
2007 // at paragraph resp. at/as character inside paragraph
2008 // are hidden.
2009 HideAndShowObjects();
2010 }
2011 ChgThisLines();
2012 return;
2013 }
2014
2015 // Waehrend wir formatieren, wollen wir nicht gestoert werden.
2016 SwTxtFrmLocker aLock(this);
2017 SwTxtLineAccess aAccess( this );
2018 const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
2019 const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );
2020
2021 if( CalcPreps() )
2022 ; // nothing
2023 // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn
2024 // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format-
2025 // informationen vorliegen.
2026 else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
2027 {
2028 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
2029 {
2030 aAccess.GetPara()->SetPrepAdjust( sal_True );
2031 aAccess.GetPara()->SetPrep( sal_True );
2032 CalcPreps();
2033 }
2034 SetWidow( sal_False );
2035 }
2036 else if( bSetOfst && IsFollow() )
2037 {
2038 SwTxtFrm *pMaster = FindMaster();
2039 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
2040 if( pMaster )
2041 pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
2042 SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
2043 if( (Frm().*fnRect->fnOverStep)( nMaxY ) )
2044 (this->*fnRect->fnSetLimit)( nMaxY );
2045 else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 )
2046 (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
2047 }
2048 else
2049 {
2050 // bSetOfst here means that we have the "red arrow situation"
2051 if ( bSetOfst )
2052 _SetOfst( 0 );
2053
2054 const sal_Bool bOrphan = IsWidow();
2055 const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
2056 SwTwips nFtnHeight = 0;
2057 if( pFtnBoss )
2058 {
2059 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
2060 nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
2061 }
2062 do
2063 {
2064 _Format( aAccess.GetPara() );
2065 if( pFtnBoss && nFtnHeight )
2066 {
2067 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
2068 SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
2069 // If we lost some footnotes, we may have more space
2070 // for our main text, so we have to format again ...
2071 if( nNewHeight < nFtnHeight )
2072 nFtnHeight = nNewHeight;
2073 else
2074 break;
2075 }
2076 else
2077 break;
2078 } while ( pFtnBoss );
2079 if( bOrphan )
2080 {
2081 ValidateFrm();
2082 SetWidow( sal_False );
2083 }
2084 }
2085 if( IsEmptyMaster() )
2086 {
2087 SwFrm* pPre = GetPrev();
2088 if( pPre &&
2089 // --> FME 2004-07-22 #i10826# It's the first, it cannot keep!
2090 pPre->GetIndPrev() &&
2091 // <--
2092 pPre->GetAttrSet()->GetKeep().GetValue() )
2093 {
2094 pPre->InvalidatePos();
2095 }
2096 }
2097 }
2098
2099 ChgThisLines();
2100
2101 // the PrepMustFit should not survive a Format operation
2102 SwParaPortion *pPara = GetPara();
2103 if ( pPara )
2104 pPara->SetPrepMustFit( sal_False );
2105
2106 #if OSL_DEBUG_LEVEL > 1
2107 // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen,
2108 // insbesondere bei Fussnoten, auf die Schliche zu kommen
2109 if( IsFollow() || GetFollow() )
2110 {
2111 SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this;
2112 const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm();
2113 MSHORT nPgNr = pTmpPage->GetPhyPageNum();
2114 MSHORT nLast;
2115 MSHORT nDummy = 0; // nur zum Breakpoint setzen
2116 while( pTmpFrm->GetFollow() )
2117 {
2118 pTmpFrm = pTmpFrm->GetFollow();
2119 nLast = nPgNr;
2120 pTmpPage = pTmpFrm->FindPageFrm();
2121 nPgNr = pTmpPage->GetPhyPageNum();
2122 if( nLast > nPgNr )
2123 ++nDummy; // schon fast eine Assertion wert
2124 else if( nLast == nPgNr )
2125 ++nDummy; // bei Spalten voellig normal, aber sonst!?
2126 else if( nLast < nPgNr - 1 )
2127 ++nDummy; // kann schon mal temporaer vorkommen
2128 }
2129 }
2130 #endif
2131
2132 CalcBaseOfstForFly();
2133 // OD 2004-03-17 #i11860#
2134 _CalcHeightOfLastLine();
2135 }
2136
2137 /*************************************************************************
2138 * SwTxtFrm::FormatQuick()
2139 *
2140 * bForceQuickFormat is set if GetFormatted() has been called during the
2141 * painting process. Actually I cannot imagine a situation which requires
2142 * a full formatting of the paragraph during painting, on the other hand
2143 * a full formatting can cause the invalidation of other layout frames,
2144 * e.g., if there are footnotes in this paragraph, and invalid layout
2145 * frames will not calculated during the painting. So I actually want to
2146 * avoid a formatting during painting, but since I'm a coward, I'll only
2147 * force the quick formatting in the situation of issue i29062.
2148 *************************************************************************/
2149
FormatQuick(bool bForceQuickFormat)2150 sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
2151 {
2152 ASSERT( ! IsVertical() || ! IsSwapped(),
2153 "SwTxtFrm::FormatQuick with swapped frame" );
2154
2155 DBG_LOOP;
2156 #if OSL_DEBUG_LEVEL > 1
2157 const XubString aXXX = GetTxtNode()->GetTxt();
2158 const SwTwips nDbgY = Frm().Top();
2159 (void)nDbgY;
2160 #ifdef DBG_UTIL
2161 // nStopAt laesst sich vom CV bearbeiten.
2162 static MSHORT nStopAt = 0;
2163 if( nStopAt == GetFrmId() )
2164 {
2165 int i = GetFrmId();
2166 (void)i;
2167 }
2168 #endif
2169 #endif
2170
2171 if( IsEmpty() && FormatEmpty() )
2172 return sal_True;
2173
2174 // Wir sind sehr waehlerisch:
2175 if( HasPara() || IsWidow() || IsLocked()
2176 || !GetValidSizeFlag() ||
2177 ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
2178 return sal_False;
2179
2180 SwTxtLineAccess aAccess( this );
2181 SwParaPortion *pPara = aAccess.GetPara();
2182 if( !pPara )
2183 return sal_False;
2184
2185 SwFrmSwapper aSwapper( this, sal_True );
2186
2187 SwTxtFrmLocker aLock(this);
2188 SwTxtFormatInfo aInf( this, sal_False, sal_True );
2189 if( 0 != aInf.MaxHyph() ) // 27483: MaxHyphen beachten!
2190 return sal_False;
2191
2192 SwTxtFormatter aLine( this, &aInf );
2193
2194 // DropCaps sind zu kompliziert...
2195 if( aLine.GetDropFmt() )
2196 return sal_False;
2197
2198 xub_StrLen nStart = GetOfst();
2199 const xub_StrLen nEnd = GetFollow()
2200 ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
2201 do
2202 {
2203 //DBG_LOOP; shadows declaration above.
2204 //resolved into:
2205 #if OSL_DEBUG_LEVEL > 1
2206 #ifdef DBG_UTIL
2207 DbgLoop aDbgLoop2( (const void*) this );
2208 #endif
2209 #endif
2210 nStart = aLine.FormatLine( nStart );
2211 if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
2212 aLine.Insert( new SwLineLayout() );
2213 } while( aLine.Next() );
2214
2215 // Last exit: die Hoehen muessen uebereinstimmen.
2216 Point aTopLeft( Frm().Pos() );
2217 aTopLeft += Prt().Pos();
2218 const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
2219 const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();
2220
2221 if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
2222 {
2223 // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic!
2224 // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" );
2225 const xub_StrLen nStrt = GetOfst();
2226 _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
2227 return sal_False;
2228 }
2229
2230 if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() )
2231 return sal_False; // kann z.B. durch Orphans auftreten (35083,35081)
2232
2233 // Geschafft, wir sind durch ...
2234
2235 // Repaint setzen
2236 pPara->GetRepaint()->Pos( aTopLeft );
2237 pPara->GetRepaint()->SSize( Prt().SSize() );
2238
2239 // Reformat loeschen
2240 *(pPara->GetReformat()) = SwCharRange();
2241 *(pPara->GetDelta()) = 0;
2242
2243 return sal_True;
2244 }
2245