xref: /trunk/main/sw/source/core/text/txtfrm.cxx (revision 4483d2e8c50e6ab05bc9c49c7af9c6b38e11e72f)
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 #include <hintids.hxx>
27 #include <hints.hxx>
28 #include <svl/ctloptions.hxx>
29 #include <sfx2/printer.hxx>
30 #include <sfx2/sfxuno.hxx>
31 #include <editeng/langitem.hxx>
32 #include <editeng/lspcitem.hxx>
33 #include <editeng/lrspitem.hxx>
34 #include <editeng/ulspitem.hxx>
35 #include <editeng/brshitem.hxx>
36 #include <editeng/pgrditem.hxx>
37 #include <swmodule.hxx>
38 #include <SwSmartTagMgr.hxx>
39 #include <doc.hxx>      // GetDoc()
40 #include "rootfrm.hxx"
41 #include <pagefrm.hxx>  // InvalidateSpelling
42 #include <rootfrm.hxx>
43 #include <viewsh.hxx>   // ViewShell
44 #include <pam.hxx>      // SwPosition
45 #include <ndtxt.hxx>        // SwTxtNode
46 #include <txtatr.hxx>
47 #include <paratr.hxx>
48 #include <viewopt.hxx>
49 #include <dflyobj.hxx>
50 #include <flyfrm.hxx>
51 #include <tabfrm.hxx>
52 #include <frmtool.hxx>
53 #include <pagedesc.hxx> // SwPageDesc
54 #include <tgrditem.hxx>
55 #include <dbg_lay.hxx>
56 #include <fmtfld.hxx>
57 #include <fmtftn.hxx>
58 #include <txtfld.hxx>
59 #include <txtftn.hxx>
60 #include <charatr.hxx>
61 #include <ftninfo.hxx>
62 #include <fmtline.hxx>
63 #include <txtfrm.hxx>       // SwTxtFrm
64 #include <sectfrm.hxx>      // SwSectFrm
65 #include <txtcfg.hxx>       // DBG_LOOP
66 #include <itrform2.hxx>       // Iteratoren
67 #include <widorp.hxx>       // SwFrmBreak
68 #include <txtcache.hxx>
69 #include <fntcache.hxx>     // GetLineSpace benutzt pLastFont
70 #include <SwGrammarMarkUp.hxx>
71 #include <lineinfo.hxx>
72 #include <SwPortionHandler.hxx>
73 #include <dcontact.hxx>
74 #include <sortedobjs.hxx>
75 #include <txtflcnt.hxx>     // SwTxtFlyCnt
76 #include <fmtflcnt.hxx>     // SwFmtFlyCnt
77 #include <fmtcntnt.hxx>     // SwFmtCntnt
78 #include <numrule.hxx>
79 #include <swtable.hxx>
80 #include <fldupde.hxx>
81 #include <IGrammarContact.hxx>
82 #include <switerator.hxx>
83 
84 #if OSL_DEBUG_LEVEL > 1
85 #include <txtpaint.hxx>     // DbgRect
86 extern const sal_Char *GetPrepName( const enum PrepareHint ePrep );
87 #endif
88 
89 
90 TYPEINIT1( SwTxtFrm, SwCntntFrm );
91 
92 // Switches width and height of the text frame
93 void SwTxtFrm::SwapWidthAndHeight()
94 {
95     if ( ! bIsSwapped )
96     {
97         const long nPrtOfstX = Prt().Pos().X();
98         Prt().Pos().X() = Prt().Pos().Y();
99         //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
100         if( IsVertLR() )
101             Prt().Pos().Y() = nPrtOfstX;
102         else
103             Prt().Pos().Y() = Frm().Width() - ( nPrtOfstX + Prt().Width() );
104 
105     }
106     else
107     {
108         const long nPrtOfstY = Prt().Pos().Y();
109         Prt().Pos().Y() = Prt().Pos().X();
110         //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
111         if( IsVertLR() )
112             Prt().Pos().X() = nPrtOfstY;
113         else
114             Prt().Pos().X() = Frm().Height() - ( nPrtOfstY + Prt().Height() );
115     }
116 
117     const long nFrmWidth = Frm().Width();
118     Frm().Width( Frm().Height() );
119     Frm().Height( nFrmWidth );
120     const long nPrtWidth = Prt().Width();
121     Prt().Width( Prt().Height() );
122     Prt().Height( nPrtWidth );
123 
124     bIsSwapped = ! bIsSwapped;
125 }
126 
127 // Calculates the coordinates of a rectangle when switching from
128 // horizontal to vertical layout.
129 void SwTxtFrm::SwitchHorizontalToVertical( SwRect& rRect ) const
130 {
131     // calc offset inside frame
132     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
133     long nOfstX, nOfstY;
134     if ( IsVertLR() )
135     {
136         nOfstX = rRect.Left() - Frm().Left();
137         nOfstY = rRect.Top() - Frm().Top();
138     }
139     else
140     {
141         nOfstX = rRect.Left() - Frm().Left();
142         nOfstY = rRect.Top() + rRect.Height() - Frm().Top();
143     }
144 
145     const long nWidth = rRect.Width();
146     const long nHeight = rRect.Height();
147 
148     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
149     if ( IsVertLR() )
150         rRect.Left(Frm().Left() + nOfstY);
151     else
152     {
153         if ( bIsSwapped )
154             rRect.Left( Frm().Left() + Frm().Height() - nOfstY );
155         else
156             // frame is rotated
157             rRect.Left( Frm().Left() + Frm().Width() - nOfstY );
158     }
159 
160     rRect.Top( Frm().Top() + nOfstX );
161     rRect.Width( nHeight );
162     rRect.Height( nWidth );
163 }
164 
165 // Calculates the coordinates of a point when switching from
166 // horizontal to vertical layout.
167 void SwTxtFrm::SwitchHorizontalToVertical( Point& rPoint ) const
168 {
169     // calc offset inside frame
170     const long nOfstX = rPoint.X() - Frm().Left();
171     const long nOfstY = rPoint.Y() - Frm().Top();
172     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
173     if ( IsVertLR() )
174         rPoint.X() = Frm().Left() + nOfstY;
175     else
176     {
177         if ( bIsSwapped )
178             rPoint.X() = Frm().Left() + Frm().Height() - nOfstY;
179         else
180             // calc rotated coords
181             rPoint.X() = Frm().Left() + Frm().Width() - nOfstY;
182     }
183 
184     rPoint.Y() = Frm().Top() + nOfstX;
185 }
186 
187 // Calculates the a limit value when switching from
188 // horizontal to vertical layout.
189 long SwTxtFrm::SwitchHorizontalToVertical( long nLimit ) const
190 {
191     Point aTmp( 0, nLimit );
192     SwitchHorizontalToVertical( aTmp );
193     return aTmp.X();
194 }
195 
196 // Calculates the coordinates of a rectangle when switching from
197 // vertical to horizontal layout.
198 void SwTxtFrm::SwitchVerticalToHorizontal( SwRect& rRect ) const
199 {
200     long nOfstX;
201 
202     // calc offset inside frame
203 
204     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
205     if ( IsVertLR() )
206         nOfstX = rRect.Left() - Frm().Left();
207     else
208     {
209         if ( bIsSwapped )
210             nOfstX = Frm().Left() + Frm().Height() - ( rRect.Left() + rRect.Width() );
211         else
212             nOfstX = Frm().Left() + Frm().Width() - ( rRect.Left() + rRect.Width() );
213     }
214 
215     const long nOfstY = rRect.Top() - Frm().Top();
216     const long nWidth = rRect.Height();
217     const long nHeight = rRect.Width();
218 
219     // calc rotated coords
220     rRect.Left( Frm().Left() + nOfstY );
221     rRect.Top( Frm().Top() + nOfstX );
222     rRect.Width( nWidth );
223     rRect.Height( nHeight );
224 }
225 
226 // Calculates the coordinates of a point when switching from
227 // vertical to horizontal layout.
228 void SwTxtFrm::SwitchVerticalToHorizontal( Point& rPoint ) const
229 {
230     long nOfstX;
231 
232     // calc offset inside frame
233 
234     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
235     if ( IsVertLR() )
236         nOfstX = rPoint.X() - Frm().Left();
237     else
238     {
239         if ( bIsSwapped )
240             nOfstX = Frm().Left() + Frm().Height() - rPoint.X();
241         else
242             nOfstX = Frm().Left() + Frm().Width() - rPoint.X();
243     }
244 
245     const long nOfstY = rPoint.Y() - Frm().Top();
246 
247     // calc rotated coords
248     rPoint.X() = Frm().Left() + nOfstY;
249     rPoint.Y() = Frm().Top() + nOfstX;
250 }
251 
252 // Calculates the a limit value when switching from
253 // vertical to horizontal layout.
254 long SwTxtFrm::SwitchVerticalToHorizontal( long nLimit ) const
255 {
256     Point aTmp( nLimit, 0 );
257     SwitchVerticalToHorizontal( aTmp );
258     return aTmp.Y();
259 }
260 
261 SwFrmSwapper::SwFrmSwapper( const SwTxtFrm* pTxtFrm, sal_Bool bSwapIfNotSwapped )
262     : pFrm( pTxtFrm ), bUndo( sal_False )
263 {
264     if ( pFrm->IsVertical() &&
265         ( (   bSwapIfNotSwapped && ! pFrm->IsSwapped() ) ||
266           ( ! bSwapIfNotSwapped && pFrm->IsSwapped() ) ) )
267     {
268         bUndo = sal_True;
269         ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
270     }
271 }
272 
273 SwFrmSwapper::~SwFrmSwapper()
274 {
275     if ( bUndo )
276         ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
277 }
278 
279 void SwTxtFrm::SwitchLTRtoRTL( SwRect& rRect ) const
280 {
281     SWAP_IF_NOT_SWAPPED( this )
282 
283     long nWidth = rRect.Width();
284     rRect.Left( 2 * ( Frm().Left() + Prt().Left() ) +
285                 Prt().Width() - rRect.Right() - 1 );
286 
287     rRect.Width( nWidth );
288 
289     UNDO_SWAP( this )
290 }
291 
292 void SwTxtFrm::SwitchLTRtoRTL( Point& rPoint ) const
293 {
294     SWAP_IF_NOT_SWAPPED( this )
295 
296     rPoint.X() = 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rPoint.X() - 1;
297 
298     UNDO_SWAP( this )
299 }
300 
301 SwLayoutModeModifier::SwLayoutModeModifier( const OutputDevice& rOutp ) :
302         rOut( rOutp ), nOldLayoutMode( rOutp.GetLayoutMode() )
303 {
304 }
305 
306 SwLayoutModeModifier::~SwLayoutModeModifier()
307 {
308     ((OutputDevice&)rOut).SetLayoutMode( nOldLayoutMode );
309 }
310 
311 void SwLayoutModeModifier::Modify( sal_Bool bChgToRTL )
312 {
313     ((OutputDevice&)rOut).SetLayoutMode( bChgToRTL ?
314                                          TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL :
315                                          TEXT_LAYOUT_BIDI_STRONG );
316 }
317 
318 void SwLayoutModeModifier::SetAuto()
319 {
320     const sal_uLong nNewLayoutMode = nOldLayoutMode & ~TEXT_LAYOUT_BIDI_STRONG;
321     ((OutputDevice&)rOut).SetLayoutMode( nNewLayoutMode );
322 }
323 
324 SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) :
325         rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() )
326 {
327     LanguageType eLang = eCurLang;
328     const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals();
329 
330     if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals )
331         eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
332     else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals )
333         eLang = LANGUAGE_ENGLISH;
334     else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals )
335         eLang = (LanguageType)::GetAppLanguage();
336 
337     ((OutputDevice&)rOut).SetDigitLanguage( eLang );
338 }
339 
340 SwDigitModeModifier::~SwDigitModeModifier()
341 {
342     ((OutputDevice&)rOut).SetDigitLanguage( nOldLanguageType );
343 }
344 
345 /*************************************************************************
346  *                      SwTxtFrm::Init()
347  *************************************************************************/
348 
349 void SwTxtFrm::Init()
350 {
351     ASSERT( !IsLocked(), "+SwTxtFrm::Init: this ist locked." );
352     if( !IsLocked() )
353     {
354         ClearPara();
355         ResetBlinkPor();
356         //Die Flags direkt setzen um ResetPreps und damit ein unnuetzes GetPara
357         //einzusparen.
358         // Nicht bOrphan, bLocked oder bWait auf sal_False setzen !
359         // bOrphan = bFlag7 = bFlag8 = sal_False;
360     }
361 }
362 
363 /*************************************************************************
364 |*  SwTxtFrm::CTORen/DTOR
365 |*************************************************************************/
366 
367 void SwTxtFrm::InitCtor()
368 {
369     nCacheIdx = MSHRT_MAX;
370     nOfst = 0;
371     nAllLines = 0;
372     nThisLines = 0;
373     mnFlyAnchorOfst = 0;
374     mnFlyAnchorOfstNoWrap = 0;
375     mnFtnLine = 0;
376     // OD 2004-03-17 #i11860#
377     mnHeightOfLastLine = 0;
378     // --> OD 2008-01-31 #newlistlevelattrs#
379     mnAdditionalFirstLineOffset = 0;
380     // <--
381 
382     nType = FRMC_TXT;
383     bLocked = bFormatted = bWidow = bUndersized = bJustWidow =
384         bEmpty = bInFtnConnect = bFtn = bRepaint = bBlinkPor =
385         bFieldFollow = bHasAnimation = bIsSwapped = sal_False;
386     // OD 14.03.2003 #i11760#
387     mbFollowFormatAllowed = sal_True;
388 }
389 
390 /*************************************************************************
391  *                      SwTxtFrm::SwTxtFrm()
392  *************************************************************************/
393 SwTxtFrm::SwTxtFrm(SwTxtNode * const pNode, SwFrm* pSib )
394     : SwCntntFrm( pNode, pSib )
395 {
396     InitCtor();
397 }
398 
399 /*************************************************************************
400  *                      SwTxtFrm::~SwTxtFrm()
401  *************************************************************************/
402 SwTxtFrm::~SwTxtFrm()
403 {
404     // Remove associated SwParaPortion from pTxtCache
405     ClearPara();
406 }
407 
408 const XubString& SwTxtFrm::GetTxt() const
409 {
410     return GetTxtNode()->GetTxt();
411 }
412 
413 void SwTxtFrm::ResetPreps()
414 {
415     if ( GetCacheIdx() != MSHRT_MAX )
416     {
417         SwParaPortion *pPara;
418         if( 0 != (pPara = GetPara()) )
419             pPara->ResetPreps();
420     }
421 }
422 
423 /*************************************************************************
424  *                        SwTxtFrm::IsHiddenNow()
425  *************************************************************************/
426 sal_Bool SwTxtFrm::IsHiddenNow() const
427 {
428     SwFrmSwapper aSwapper( this, sal_True );
429 
430     if( !Frm().Width() && IsValid() && GetUpper()->IsValid() )
431                                        //bei Stackueberlauf (StackHack) invalid!
432     {
433 //        ASSERT( false, "SwTxtFrm::IsHiddenNow: thin frame" );
434         return sal_True;
435     }
436 
437     const bool bHiddenCharsHidePara = GetTxtNode()->HasHiddenCharAttribute( true );
438     const bool bHiddenParaField = GetTxtNode()->HasHiddenParaField();
439     const ViewShell* pVsh = getRootFrm()->GetCurrShell();
440 
441     if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) )
442     {
443         if (
444              ( bHiddenParaField &&
445                ( !pVsh->GetViewOptions()->IsShowHiddenPara() &&
446                  !pVsh->GetViewOptions()->IsFldName() ) ) ||
447              ( bHiddenCharsHidePara &&
448                !pVsh->GetViewOptions()->IsShowHiddenChar() ) )
449         {
450             return sal_True;
451         }
452     }
453 
454     return sal_False;
455 }
456 
457 
458 /*************************************************************************
459  *                        SwTxtFrm::HideHidden()
460  *************************************************************************/
461 // Entfernt die Anhaengsel des Textfrms wenn dieser hidden ist
462 
463 void SwTxtFrm::HideHidden()
464 {
465     ASSERT( !GetFollow() && IsHiddenNow(),
466             "HideHidden on visible frame of hidden frame has follow" );
467 
468     const xub_StrLen nEnd = STRING_LEN;
469     HideFootnotes( GetOfst(), nEnd );
470     // OD 2004-01-15 #110582#
471     HideAndShowObjects();
472 
473     //Die Formatinfos sind jetzt obsolete
474     ClearPara();
475 }
476 
477 /*************************************************************************
478  *                        SwTxtFrm::HideFootnotes()
479  *************************************************************************/
480 void SwTxtFrm::HideFootnotes( xub_StrLen nStart, xub_StrLen nEnd )
481 {
482     const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
483     if( pHints )
484     {
485         const sal_uInt16 nSize = pHints->Count();
486         SwPageFrm *pPage = 0;
487         for ( sal_uInt16 i = 0; i < nSize; ++i )
488         {
489             const SwTxtAttr *pHt = (*pHints)[i];
490             if ( pHt->Which() == RES_TXTATR_FTN )
491             {
492                 const xub_StrLen nIdx = *pHt->GetStart();
493                 if ( nEnd < nIdx )
494                     break;
495                 if( nStart <= nIdx )
496                 {
497                     if( !pPage )
498                         pPage = FindPageFrm();
499                     pPage->RemoveFtn( this, (SwTxtFtn*)pHt );
500                 }
501             }
502         }
503     }
504 }
505 
506 // --> OD 2005-03-30 #120729# - hotfix: WW8 documents contain at its end hidden,
507 // as-character anchored graphics, which are used for a graphic bullet list.
508 // As long as these graphic bullet list aren't imported, do not hide a
509 // at-character anchored object, if
510 // (a) the document is an imported WW8 document -
511 //     checked by checking certain compatibility options -,
512 // (b) the paragraph is the last content in the document and
513 // (c) the anchor character is an as-character anchored graphic.
514 bool lcl_HideObj( const SwTxtFrm& _rFrm,
515                   const RndStdIds _eAnchorType,
516                   const xub_StrLen _nObjAnchorPos,
517                   SwAnchoredObject* _pAnchoredObj )
518 {
519     bool bRet( true );
520 
521     if (_eAnchorType == FLY_AT_CHAR)
522     {
523         const IDocumentSettingAccess* pIDSA = _rFrm.GetTxtNode()->getIDocumentSettingAccess();
524         if ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
525              !pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING) &&
526              !pIDSA->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) &&
527               pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
528              _rFrm.IsInDocBody() && !_rFrm.FindNextCnt() )
529         {
530             const xub_Unicode cAnchorChar =
531                         _rFrm.GetTxtNode()->GetTxt().GetChar( _nObjAnchorPos );
532             if ( cAnchorChar == CH_TXTATR_BREAKWORD )
533             {
534                 const SwTxtAttr* const pHint(
535                     _rFrm.GetTxtNode()->GetTxtAttrForCharAt(_nObjAnchorPos,
536                         RES_TXTATR_FLYCNT) );
537                 if ( pHint )
538                 {
539                     const SwFrmFmt* pFrmFmt =
540                         static_cast<const SwTxtFlyCnt*>(pHint)->GetFlyCnt().GetFrmFmt();
541                     if ( pFrmFmt->Which() == RES_FLYFRMFMT )
542                     {
543                         SwNodeIndex nCntntIndex = *(pFrmFmt->GetCntnt().GetCntntIdx());
544                         nCntntIndex++;
545                         if ( nCntntIndex.GetNode().IsNoTxtNode() )
546                         {
547                             bRet = false;
548                             // set needed data structure values for object positioning
549                             SWRECTFN( (&_rFrm) );
550                             SwRect aLastCharRect( _rFrm.Frm() );
551                             (aLastCharRect.*fnRect->fnSetWidth)( 1 );
552                             _pAnchoredObj->maLastCharRect = aLastCharRect;
553                             _pAnchoredObj->mnLastTopOfLine = (aLastCharRect.*fnRect->fnGetTop)();
554                         }
555                     }
556                 }
557             }
558         }
559     }
560 
561     return bRet;
562 }
563 // <--
564 /*************************************************************************
565  *                        SwTxtFrm::HideAndShowObjects()
566  *************************************************************************/
567 /** method to hide/show objects
568 
569     OD 2004-01-15 #110582#
570     method hides respectively shows objects, which are anchored at paragraph,
571     at/as a character of the paragraph, corresponding to the paragraph and
572     paragraph portion visibility.
573 
574     - is called from HideHidden() - should hide objects in hidden paragraphs and
575     - from _Format() - should hide/show objects in partly visible paragraphs
576 
577     @author OD
578 */
579 void SwTxtFrm::HideAndShowObjects()
580 {
581     if ( GetDrawObjs() )
582     {
583         if ( IsHiddenNow() )
584         {
585             // complete paragraph is hidden. Thus, hide all objects
586             for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
587             {
588                 SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
589                 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
590                 // --> OD 2005-03-30 #120729# - hotfix: do not hide object
591                 // under certain conditions
592                 const RndStdIds eAnchorType( pContact->GetAnchorId() );
593                 const xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
594                 if ((eAnchorType != FLY_AT_CHAR) ||
595                     lcl_HideObj( *this, eAnchorType, nObjAnchorPos,
596                                  (*GetDrawObjs())[i] ))
597                 {
598                     pContact->MoveObjToInvisibleLayer( pObj );
599                 }
600                 // <--
601             }
602         }
603         else
604         {
605             // paragraph is visible, but can contain hidden text portion.
606             // first we check if objects are allowed to be hidden:
607             const SwTxtNode& rNode = *GetTxtNode();
608             const ViewShell* pVsh = getRootFrm()->GetCurrShell();
609             const bool bShouldBeHidden = !pVsh || !pVsh->GetWin() ||
610                                          !pVsh->GetViewOptions()->IsShowHiddenChar();
611 
612             // Thus, show all objects, which are anchored at paragraph and
613             // hide/show objects, which are anchored at/as character, according
614             // to the visibility of the anchor character.
615             for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
616             {
617                 SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
618                 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
619                 // --> OD 2005-03-30 #120729# - determine anchor type only once
620                 const RndStdIds eAnchorType( pContact->GetAnchorId() );
621                 // <--
622 
623                 if (eAnchorType == FLY_AT_PARA)
624                 {
625                     pContact->MoveObjToVisibleLayer( pObj );
626                 }
627                 else if ((eAnchorType == FLY_AT_CHAR) ||
628                          (eAnchorType == FLY_AS_CHAR))
629                 {
630                     xub_StrLen nHiddenStart;
631                     xub_StrLen nHiddenEnd;
632                     xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
633                     SwScriptInfo::GetBoundsOfHiddenRange( rNode, nObjAnchorPos, nHiddenStart, nHiddenEnd, 0 );
634                     // --> OD 2005-03-30 #120729# - hotfix: do not hide object
635                     // under certain conditions
636                     if ( nHiddenStart != STRING_LEN && bShouldBeHidden &&
637                          lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) )
638                     // <--
639                         pContact->MoveObjToInvisibleLayer( pObj );
640                     else
641                         pContact->MoveObjToVisibleLayer( pObj );
642                 }
643                 else
644                 {
645                     ASSERT( false,
646                             "<SwTxtFrm::HideAndShowObjects()> - object not anchored at/inside paragraph!?" );
647                 }
648             }
649         }
650     }
651 
652     if ( IsFollow() )
653     {
654         FindMaster()->HideAndShowObjects();
655     }
656 }
657 
658 /*************************************************************************
659  *                      SwTxtFrm::FindBrk()
660  *
661  * Liefert die erste Trennmoeglichkeit in der aktuellen Zeile zurueck.
662  * Die Methode wird in SwTxtFrm::Format() benutzt, um festzustellen, ob
663  * die Vorgaengerzeile mitformatiert werden muss.
664  * nFound ist <= nEndLine.
665  *************************************************************************/
666 
667 xub_StrLen SwTxtFrm::FindBrk( const XubString &rTxt,
668                               const xub_StrLen nStart,
669                               const xub_StrLen nEnd ) const
670 {
671     // --> OD 2009-12-28 #i104291# - applying patch to avoid overflow.
672     unsigned long nFound = nStart;
673     const xub_StrLen nEndLine = Min( nEnd, rTxt.Len() );
674 
675     // Wir ueberlesen erst alle Blanks am Anfang der Zeile (vgl. Bug 2235).
676     while( nFound <= nEndLine &&
677            ' ' == rTxt.GetChar( static_cast<xub_StrLen>(nFound) ) )
678     {
679          nFound++;
680     }
681 
682     // Eine knifflige Sache mit den TxtAttr-Dummy-Zeichen (hier "$"):
683     // "Dr.$Meyer" am Anfang der zweiten Zeile. Dahinter ein Blank eingegeben
684     // und das Wort rutscht nicht in die erste Zeile, obwohl es ginge.
685     // Aus diesem Grund nehmen wir das Dummy-Zeichen noch mit.
686     while( nFound <= nEndLine &&
687            ' ' != rTxt.GetChar( static_cast<xub_StrLen>(nFound) ) )
688     {
689         nFound++;
690     }
691 
692     return nFound <= STRING_LEN
693            ? static_cast<xub_StrLen>(nFound)
694            : STRING_LEN;
695     // <--
696 }
697 
698 /*************************************************************************
699  *                      SwTxtFrm::IsIdxInside()
700  *************************************************************************/
701 
702 sal_Bool SwTxtFrm::IsIdxInside( const xub_StrLen nPos, const xub_StrLen nLen ) const
703 {
704     if( GetOfst() > nPos + nLen ) // d.h., der Bereich liegt komplett vor uns.
705         return sal_False;
706 
707     if( !GetFollow() )         // der Bereich liegt nicht komplett vor uns,
708         return sal_True;           // nach uns kommt niemand mehr.
709 
710     const xub_StrLen nMax = GetFollow()->GetOfst();
711 
712     // der Bereich liegt nicht komplett hinter uns bzw.
713     // unser Text ist geloescht worden.
714     if( nMax > nPos || nMax > GetTxt().Len() )
715         return sal_True;
716 
717     // changes made in the first line of a follow can modify the master
718     const SwParaPortion* pPara = GetFollow()->GetPara();
719     return pPara && ( nPos <= nMax + pPara->GetLen() );
720 }
721 
722 /*************************************************************************
723  *                      SwTxtFrm::InvalidateRange()
724  *************************************************************************/
725 inline void SwTxtFrm::InvalidateRange(const SwCharRange &aRange, const long nD)
726 {
727     if ( IsIdxInside( aRange.Start(), aRange.Len() ) )
728         _InvalidateRange( aRange, nD );
729 }
730 
731 /*************************************************************************
732  *                      SwTxtFrm::_InvalidateRange()
733  *************************************************************************/
734 
735 void SwTxtFrm::_InvalidateRange( const SwCharRange &aRange, const long nD)
736 {
737     if ( !HasPara() )
738     {   InvalidateSize();
739         return;
740     }
741 
742     SetWidow( sal_False );
743     SwParaPortion *pPara = GetPara();
744 
745     sal_Bool bInv = sal_False;
746     if( 0 != nD )
747     {
748         //Auf nDelta werden die Differenzen zwischen alter und
749         //neuer Zeilenlaenge aufaddiert, deshalb ist es negativ,
750         //wenn Zeichen eingefuegt wurden, positiv, wenn Zeichen
751         //geloescht wurden.
752         *(pPara->GetDelta()) += nD;
753         bInv = sal_True;
754     }
755     SwCharRange &rReformat = *(pPara->GetReformat());
756     if(aRange != rReformat) {
757         if( STRING_LEN == rReformat.Len() )
758             rReformat = aRange;
759         else
760             rReformat += aRange;
761         bInv = sal_True;
762     }
763     if(bInv)
764     {
765 // 90365: nD is passed to a follow two times
766 //        if( GetFollow() )
767 //            ((SwTxtFrm*)GetFollow())->InvalidateRange( aRange, nD );
768         InvalidateSize();
769     }
770 }
771 
772 /*************************************************************************
773  *                      SwTxtFrm::CalcLineSpace()
774  *************************************************************************/
775 
776 void SwTxtFrm::CalcLineSpace()
777 {
778     ASSERT( ! IsVertical() || ! IsSwapped(),
779             "SwTxtFrm::CalcLineSpace with swapped frame!" )
780 
781     if( IsLocked() || !HasPara() )
782         return;
783 
784     SwParaPortion *pPara;
785     if( GetDrawObjs() ||
786         GetTxtNode()->GetSwAttrSet().GetLRSpace().IsAutoFirst() ||
787         ( pPara = GetPara() )->IsFixLineHeight() )
788     {
789         Init();
790         return;
791     }
792 
793     Size aNewSize( Prt().SSize() );
794 
795     SwTxtFormatInfo aInf( this );
796     SwTxtFormatter aLine( this, &aInf );
797     if( aLine.GetDropLines() )
798     {
799         Init();
800         return;
801     }
802 
803     aLine.Top();
804     aLine.RecalcRealHeight();
805 
806     aNewSize.Height() = (aLine.Y() - Frm().Top()) + aLine.GetLineHeight();
807 
808     SwTwips nDelta = aNewSize.Height() - Prt().Height();
809     // 4291: Unterlauf bei Flys
810     if( aInf.GetTxtFly()->IsOn() )
811     {
812         SwRect aTmpFrm( Frm() );
813         if( nDelta < 0 )
814             aTmpFrm.Height( Prt().Height() );
815         else
816             aTmpFrm.Height( aNewSize.Height() );
817         if( aInf.GetTxtFly()->Relax( aTmpFrm ) )
818         {
819             Init();
820             return;
821         }
822     }
823 
824     if( nDelta )
825     {
826         SwTxtFrmBreak aBreak( this );
827         if( GetFollow() || aBreak.IsBreakNow( aLine ) )
828         {
829             // Wenn es einen Follow() gibt, oder wenn wir an dieser
830             // Stelle aufbrechen muessen, so wird neu formatiert.
831             Init();
832         }
833         else
834         {
835             // Alles nimmt seinen gewohnten Gang ...
836             pPara->SetPrepAdjust();
837             pPara->SetPrep();
838         }
839     }
840 }
841 
842 //
843 // SET_WRONG( nPos, nCnt, bMove )
844 //
845 #define SET_WRONG( nPos, nCnt, bMove ) \
846 { \
847     lcl_SetWrong( *this, nPos, nCnt, bMove ); \
848 }
849 
850 void lcl_SetWrong( SwTxtFrm& rFrm, xub_StrLen nPos, long nCnt, bool bMove )
851 {
852     if ( !rFrm.IsFollow() )
853     {
854         SwTxtNode* pTxtNode = rFrm.GetTxtNode();
855         IGrammarContact* pGrammarContact = getGrammarContact( *pTxtNode );
856         SwGrammarMarkUp* pWrongGrammar = pGrammarContact ?
857             pGrammarContact->getGrammarCheck( *pTxtNode, false ) :
858             pTxtNode->GetGrammarCheck();
859         bool bGrammarProxy = pWrongGrammar != pTxtNode->GetGrammarCheck();
860         if( bMove )
861         {
862             if( pTxtNode->GetWrong() )
863                 pTxtNode->GetWrong()->Move( nPos, nCnt );
864             if( pWrongGrammar )
865                 pWrongGrammar->MoveGrammar( nPos, nCnt );
866             if( bGrammarProxy && pTxtNode->GetGrammarCheck() )
867                 pTxtNode->GetGrammarCheck()->MoveGrammar( nPos, nCnt );
868             if( pTxtNode->GetSmartTags() )
869                 pTxtNode->GetSmartTags()->Move( nPos, nCnt );
870         }
871         else
872         {
873             xub_StrLen nLen = (xub_StrLen)nCnt;
874             if( pTxtNode->GetWrong() )
875                 pTxtNode->GetWrong()->Invalidate( nPos, nLen );
876             if( pWrongGrammar )
877                 pWrongGrammar->Invalidate( nPos, nLen );
878             if( pTxtNode->GetSmartTags() )
879                 pTxtNode->GetSmartTags()->Invalidate( nPos, nLen );
880         }
881         if ( !pTxtNode->GetWrong() && !pTxtNode->IsWrongDirty() )
882         {
883             pTxtNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
884             pTxtNode->GetWrong()->SetInvalid( nPos, nPos + (sal_uInt16)( nCnt > 0 ? nCnt : 1 ) );
885         }
886         if ( !pTxtNode->GetSmartTags() && !pTxtNode->IsSmartTagDirty() )
887         {
888             // SMARTTAGS
889             pTxtNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) );
890             pTxtNode->GetSmartTags()->SetInvalid( nPos, nPos + (sal_uInt16)( nCnt > 0 ? nCnt : 1 ) );
891         }
892         pTxtNode->SetWrongDirty( true );
893         pTxtNode->SetGrammarCheckDirty( true );
894         pTxtNode->SetWordCountDirty( true );
895         pTxtNode->SetAutoCompleteWordDirty( true );
896         // SMARTTAGS
897         pTxtNode->SetSmartTagDirty( true );
898     }
899 
900     SwRootFrm *pRootFrm = rFrm.getRootFrm();
901     if (pRootFrm)
902     {
903         pRootFrm->SetNeedGrammarCheck( sal_True );
904     }
905 
906     SwPageFrm *pPage = rFrm.FindPageFrm();
907     if( pPage )
908     {
909         pPage->InvalidateSpelling();
910         pPage->InvalidateAutoCompleteWords();
911         pPage->InvalidateWordCount();
912         pPage->InvalidateSmartTags();
913     }
914 }
915 
916 //
917 // SET_SCRIPT_INVAL( nPos )
918 //
919 
920 #define SET_SCRIPT_INVAL( nPos )\
921     lcl_SetScriptInval( *this, nPos );
922 
923 void lcl_SetScriptInval( SwTxtFrm& rFrm, xub_StrLen nPos )
924 {
925     if( rFrm.GetPara() )
926         rFrm.GetPara()->GetScriptInfo().SetInvalidity( nPos );
927 }
928 
929 void lcl_ModifyOfst( SwTxtFrm* pFrm, xub_StrLen nPos, xub_StrLen nLen )
930 {
931     while( pFrm && pFrm->GetOfst() <= nPos )
932         pFrm = pFrm->GetFollow();
933     while( pFrm )
934     {
935         pFrm->ManipOfst( pFrm->GetOfst() + nLen );
936         pFrm = pFrm->GetFollow();
937     }
938 }
939 
940 /*************************************************************************
941  *                      SwTxtFrm::Modify()
942  *************************************************************************/
943 
944 void SwTxtFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
945 {
946     const MSHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
947 
948     //Wuensche die FrmAttribute betreffen werden von der Basisklasse
949     //verarbeitet.
950     if( IsInRange( aFrmFmtSetRange, nWhich ) || RES_FMT_CHG == nWhich )
951     {
952         SwCntntFrm::Modify( pOld, pNew );
953         if( nWhich == RES_FMT_CHG && getRootFrm()->GetCurrShell() )
954         {
955             // Collection hat sich geaendert
956             Prepare( PREP_CLEAR );
957             _InvalidatePrt();
958             SET_WRONG( 0, STRING_LEN, false );
959             SetDerivedR2L( sal_False );
960             CheckDirChange();
961             // OD 09.12.2002 #105576# - Force complete paint due to existing
962             // indents.
963             SetCompletePaint();
964             InvalidateLineNum();
965         }
966         return;
967     }
968 
969     // Im gelockten Zustand werden keine Bestellungen angenommen.
970     if( IsLocked() )
971         return;
972 
973     // Dies spart Stack, man muss nur aufpassen,
974     // dass sie Variablen gesetzt werden.
975     xub_StrLen nPos, nLen;
976     sal_Bool bSetFldsDirty = sal_False;
977     sal_Bool bRecalcFtnFlag = sal_False;
978 
979     switch( nWhich )
980     {
981         case RES_LINENUMBER:
982         {
983             InvalidateLineNum();
984         }
985         break;
986         case RES_INS_TXT:
987         {
988             nPos = ((SwInsTxt*)pNew)->nPos;
989             nLen = ((SwInsTxt*)pNew)->nLen;
990             if( IsIdxInside( nPos, nLen ) )
991             {
992                 if( !nLen )
993                 {
994                     // 6969: Aktualisierung der NumPortions auch bei leeren Zeilen!
995                     if( nPos )
996                         InvalidateSize();
997                     else
998                         Prepare( PREP_CLEAR );
999                 }
1000                 else
1001                     _InvalidateRange( SwCharRange( nPos, nLen ), nLen );
1002             }
1003             SET_WRONG( nPos, nLen, true )
1004             SET_SCRIPT_INVAL( nPos )
1005             bSetFldsDirty = sal_True;
1006             if( HasFollow() )
1007                 lcl_ModifyOfst( this, nPos, nLen );
1008         }
1009         break;
1010         case RES_DEL_CHR:
1011         {
1012             nPos = ((SwDelChr*)pNew)->nPos;
1013             InvalidateRange( SwCharRange( nPos, 1 ), -1 );
1014             SET_WRONG( nPos, -1, true )
1015             SET_SCRIPT_INVAL( nPos )
1016             bSetFldsDirty = bRecalcFtnFlag = sal_True;
1017             if( HasFollow() )
1018                 lcl_ModifyOfst( this, nPos, STRING_LEN );
1019         }
1020         break;
1021         case RES_DEL_TXT:
1022         {
1023             nPos = ((SwDelTxt*)pNew)->nStart;
1024             nLen = ((SwDelTxt*)pNew)->nLen;
1025             long m = nLen;
1026             m *= -1;
1027             if( IsIdxInside( nPos, nLen ) )
1028             {
1029                 if( !nLen )
1030                     InvalidateSize();
1031                 else
1032                     InvalidateRange( SwCharRange( nPos, 1 ), m );
1033             }
1034             SET_WRONG( nPos, m, true )
1035             SET_SCRIPT_INVAL( nPos )
1036             bSetFldsDirty = bRecalcFtnFlag = sal_True;
1037             if( HasFollow() )
1038                 lcl_ModifyOfst( this, nPos, nLen );
1039         }
1040         break;
1041         case RES_UPDATE_ATTR:
1042         {
1043             nPos = ((SwUpdateAttr*)pNew)->nStart;
1044             nLen = ((SwUpdateAttr*)pNew)->nEnd - nPos;
1045             if( IsIdxInside( nPos, nLen ) )
1046             {
1047                 // Es muss in jedem Fall neu formatiert werden,
1048                 // auch wenn der invalidierte Bereich null ist.
1049                 // Beispiel: leere Zeile, 14Pt einstellen !
1050                 // if( !nLen ) nLen = 1;
1051 
1052                 // 6680: FtnNummern muessen formatiert werden.
1053                 if( !nLen )
1054                     nLen = 1;
1055 
1056                 _InvalidateRange( SwCharRange( nPos, nLen) );
1057                 MSHORT nTmp = ((SwUpdateAttr*)pNew)->nWhichAttr;
1058 
1059                 if( ! nTmp || RES_TXTATR_CHARFMT == nTmp || RES_TXTATR_AUTOFMT == nTmp ||
1060                     RES_FMT_CHG == nTmp || RES_ATTRSET_CHG == nTmp )
1061                 {
1062                     SET_WRONG( nPos, nPos + nLen, false )
1063                     SET_SCRIPT_INVAL( nPos )
1064                 }
1065             }
1066 
1067             // --> OD 2010-02-16 #i104008#
1068             ViewShell* pViewSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
1069             if ( pViewSh  )
1070             {
1071                 pViewSh->InvalidateAccessibleParaAttrs( *this );
1072             }
1073             // <--
1074         }
1075         break;
1076         case RES_OBJECTDYING:
1077         break;
1078 
1079         case RES_PARATR_LINESPACING:
1080             {
1081                 CalcLineSpace();
1082                 InvalidateSize();
1083                 _InvalidatePrt();
1084                 if( IsInSct() && !GetPrev() )
1085                 {
1086                     SwSectionFrm *pSect = FindSctFrm();
1087                     if( pSect->ContainsAny() == this )
1088                         pSect->InvalidatePrt();
1089                 }
1090 
1091                 // OD 09.01.2004 #i11859# - correction:
1092                 //  (1) Also invalidate next frame on next page/column.
1093                 //  (2) Skip empty sections and hidden paragraphs
1094                 //  Thus, use method <InvalidateNextPrtArea()>
1095                 InvalidateNextPrtArea();
1096 
1097                 SetCompletePaint();
1098             }
1099             break;
1100         case RES_TXTATR_FIELD:
1101         {
1102             nPos = *((SwFmtFld*)pNew)->GetTxtFld()->GetStart();
1103             if( IsIdxInside( nPos, 1 ) )
1104             {
1105                 if( pNew == pOld )
1106                 {
1107                     // Nur repainten
1108                     // opt: invalidate aufs Window ?
1109                     InvalidatePage();
1110                     SetCompletePaint();
1111                 }
1112                 else
1113                     _InvalidateRange( SwCharRange( nPos, 1 ) );
1114             }
1115             bSetFldsDirty = sal_True;
1116             // ST2
1117             if ( SwSmartTagMgr::Get().IsSmartTagsEnabled() )
1118                 SET_WRONG( nPos, nPos + 1, false )
1119         }
1120         break;
1121         case RES_TXTATR_FTN :
1122         {
1123             nPos = *((SwFmtFtn*)pNew)->GetTxtFtn()->GetStart();
1124             if( IsInFtn() || IsIdxInside( nPos, 1 ) )
1125                 Prepare( PREP_FTN, ((SwFmtFtn*)pNew)->GetTxtFtn() );
1126             break;
1127         }
1128 
1129         case RES_ATTRSET_CHG:
1130         {
1131             InvalidateLineNum();
1132 
1133             SwAttrSet& rNewSet = *((SwAttrSetChg*)pNew)->GetChgSet();
1134             const SfxPoolItem* pItem;
1135             int nClear = 0;
1136             MSHORT nCount = rNewSet.Count();
1137 
1138             if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FTN,
1139                 sal_False, &pItem ))
1140             {
1141                 nPos = *((SwFmtFtn*)pItem)->GetTxtFtn()->GetStart();
1142                 if( IsIdxInside( nPos, 1 ) )
1143                     Prepare( PREP_FTN, pNew );
1144                 nClear = 0x01;
1145                 --nCount;
1146             }
1147 
1148             if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FIELD,
1149                 sal_False, &pItem ))
1150             {
1151                 nPos = *((SwFmtFld*)pItem)->GetTxtFld()->GetStart();
1152                 if( IsIdxInside( nPos, 1 ) )
1153                 {
1154                     const SfxPoolItem& rOldItem = ((SwAttrSetChg*)pOld)->
1155                                         GetChgSet()->Get( RES_TXTATR_FIELD );
1156                     if( pItem == &rOldItem )
1157                     {
1158                         // Nur repainten
1159                         // opt: invalidate aufs Window ?
1160                         InvalidatePage();
1161                         SetCompletePaint();
1162                     }
1163                     else
1164                         _InvalidateRange( SwCharRange( nPos, 1 ) );
1165                 }
1166                 nClear |= 0x02;
1167                 --nCount;
1168             }
1169             sal_Bool bLineSpace = SFX_ITEM_SET == rNewSet.GetItemState(
1170                                             RES_PARATR_LINESPACING, sal_False ),
1171                      bRegister  = SFX_ITEM_SET == rNewSet.GetItemState(
1172                                             RES_PARATR_REGISTER, sal_False );
1173             if ( bLineSpace || bRegister )
1174             {
1175                 Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
1176                 CalcLineSpace();
1177                 InvalidateSize();
1178                 _InvalidatePrt();
1179 
1180                 // OD 09.01.2004 #i11859# - correction:
1181                 //  (1) Also invalidate next frame on next page/column.
1182                 //  (2) Skip empty sections and hidden paragraphs
1183                 //  Thus, use method <InvalidateNextPrtArea()>
1184                 InvalidateNextPrtArea();
1185 
1186                 SetCompletePaint();
1187                 nClear |= 0x04;
1188                 if ( bLineSpace )
1189                 {
1190                     --nCount;
1191                     if( IsInSct() && !GetPrev() )
1192                     {
1193                         SwSectionFrm *pSect = FindSctFrm();
1194                         if( pSect->ContainsAny() == this )
1195                             pSect->InvalidatePrt();
1196                     }
1197                 }
1198                 if ( bRegister )
1199                     --nCount;
1200             }
1201             if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_SPLIT,
1202                                                        sal_False ))
1203             {
1204                 if ( GetPrev() )
1205                     CheckKeep();
1206                 Prepare( PREP_CLEAR );
1207                 InvalidateSize();
1208                 nClear |= 0x08;
1209                 --nCount;
1210             }
1211 
1212             if( SFX_ITEM_SET == rNewSet.GetItemState( RES_BACKGROUND, sal_False)
1213                 && !IsFollow() && GetDrawObjs() )
1214             {
1215                 SwSortedObjs *pObjs = GetDrawObjs();
1216                 for ( int i = 0; GetDrawObjs() && i < int(pObjs->Count()); ++i )
1217                 {
1218                     SwAnchoredObject* pAnchoredObj = (*pObjs)[MSHORT(i)];
1219                     if ( pAnchoredObj->ISA(SwFlyFrm) )
1220                     {
1221                         SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
1222                         if( !pFly->IsFlyInCntFrm() )
1223                         {
1224                             const SvxBrushItem &rBack =
1225                                 pFly->GetAttrSet()->GetBackground();
1226                             // OD 20.08.2002 #99657# #GetTransChg#
1227                             //     following condition determines, if the fly frame
1228                             //     "inherites" the background color of text frame.
1229                             //     This is the case, if fly frame background
1230                             //     color is "no fill"/"auto fill" and if the fly frame
1231                             //     has no background graphic.
1232                             //     Thus, check complete fly frame background
1233                             //     color and *not* only its transparency value
1234                             if ( (rBack.GetColor() == COL_TRANSPARENT)  &&
1235                             //if( rBack.GetColor().GetTransparency() &&
1236                                 rBack.GetGraphicPos() == GPOS_NONE )
1237                             {
1238                                 pFly->SetCompletePaint();
1239                                 pFly->InvalidatePage();
1240                             }
1241                         }
1242                     }
1243                 }
1244             }
1245 
1246             if ( SFX_ITEM_SET ==
1247                  rNewSet.GetItemState( RES_TXTATR_CHARFMT, sal_False ) )
1248             {
1249                 SET_WRONG( 0, STRING_LEN, false )
1250                 SET_SCRIPT_INVAL( 0 )
1251             }
1252             else if ( SFX_ITEM_SET ==
1253                       rNewSet.GetItemState( RES_CHRATR_LANGUAGE, sal_False ) ||
1254                       SFX_ITEM_SET ==
1255                       rNewSet.GetItemState( RES_CHRATR_CJK_LANGUAGE, sal_False ) ||
1256                       SFX_ITEM_SET ==
1257                       rNewSet.GetItemState( RES_CHRATR_CTL_LANGUAGE, sal_False ) )
1258                 SET_WRONG( 0, STRING_LEN, false )
1259             else if ( SFX_ITEM_SET ==
1260                       rNewSet.GetItemState( RES_CHRATR_FONT, sal_False ) ||
1261                       SFX_ITEM_SET ==
1262                       rNewSet.GetItemState( RES_CHRATR_CJK_FONT, sal_False ) ||
1263                       SFX_ITEM_SET ==
1264                       rNewSet.GetItemState( RES_CHRATR_CTL_FONT, sal_False ) )
1265                 SET_SCRIPT_INVAL( 0 )
1266             else if ( SFX_ITEM_SET ==
1267                       rNewSet.GetItemState( RES_FRAMEDIR, sal_False ) )
1268             {
1269                 SetDerivedR2L( sal_False );
1270                 CheckDirChange();
1271                 // OD 09.12.2002 #105576# - Force complete paint due to existing
1272                 // indents.
1273                 SetCompletePaint();
1274             }
1275 
1276 
1277             if( nCount )
1278             {
1279                 if( getRootFrm()->GetCurrShell() )
1280                 {
1281                     Prepare( PREP_CLEAR );
1282                     _InvalidatePrt();
1283                 }
1284 
1285                 if( nClear )
1286                 {
1287                     SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
1288                     SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
1289 
1290                     if( 0x01 & nClear )
1291                     {
1292                         aOldSet.ClearItem( RES_TXTATR_FTN );
1293                         aNewSet.ClearItem( RES_TXTATR_FTN );
1294                     }
1295                     if( 0x02 & nClear )
1296                     {
1297                         aOldSet.ClearItem( RES_TXTATR_FIELD );
1298                         aNewSet.ClearItem( RES_TXTATR_FIELD );
1299                     }
1300                     if ( 0x04 & nClear )
1301                     {
1302                         if ( bLineSpace )
1303                         {
1304                             aOldSet.ClearItem( RES_PARATR_LINESPACING );
1305                             aNewSet.ClearItem( RES_PARATR_LINESPACING );
1306                         }
1307                         if ( bRegister )
1308                         {
1309                             aOldSet.ClearItem( RES_PARATR_REGISTER );
1310                             aNewSet.ClearItem( RES_PARATR_REGISTER );
1311                         }
1312                     }
1313                     if ( 0x08 & nClear )
1314                     {
1315                         aOldSet.ClearItem( RES_PARATR_SPLIT );
1316                         aNewSet.ClearItem( RES_PARATR_SPLIT );
1317                     }
1318                     SwCntntFrm::Modify( &aOldSet, &aNewSet );
1319                 }
1320                 else
1321                     SwCntntFrm::Modify( pOld, pNew );
1322             }
1323 
1324             // --> OD 2009-01-06 #i88069#
1325             ViewShell* pViewSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
1326             if ( pViewSh  )
1327             {
1328                 pViewSh->InvalidateAccessibleParaAttrs( *this );
1329             }
1330             // <--
1331         }
1332         break;
1333 
1334         // 6870: SwDocPosUpdate auswerten.
1335         case RES_DOCPOS_UPDATE:
1336         {
1337             if( pOld && pNew )
1338             {
1339                 const SwDocPosUpdate *pDocPos = (const SwDocPosUpdate*)pOld;
1340                 if( pDocPos->nDocPos <= aFrm.Top() )
1341                 {
1342                     const SwFmtFld *pFld = (const SwFmtFld *)pNew;
1343                     InvalidateRange(
1344                         SwCharRange( *pFld->GetTxtFld()->GetStart(), 1 ) );
1345                 }
1346             }
1347             break;
1348         }
1349         case RES_PARATR_SPLIT:
1350             if ( GetPrev() )
1351                 CheckKeep();
1352             Prepare( PREP_CLEAR );
1353             bSetFldsDirty = sal_True;
1354             break;
1355         case RES_FRAMEDIR :
1356             SetDerivedR2L( sal_False );
1357             CheckDirChange();
1358             break;
1359         default:
1360         {
1361             Prepare( PREP_CLEAR );
1362             _InvalidatePrt();
1363             if ( !nWhich )
1364             {
1365                 //Wird z.B. bei HiddenPara mit 0 gerufen.
1366                 SwFrm *pNxt;
1367                 if ( 0 != (pNxt = FindNext()) )
1368                     pNxt->InvalidatePrt();
1369             }
1370         }
1371     } // switch
1372 
1373     if( bSetFldsDirty )
1374         GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( sal_True, GetNode(), 1 );
1375 
1376     if ( bRecalcFtnFlag )
1377         CalcFtnFlag();
1378 }
1379 
1380 sal_Bool SwTxtFrm::GetInfo( SfxPoolItem &rHnt ) const
1381 {
1382     if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && ! IsFollow() )
1383     {
1384         SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
1385         const SwPageFrm *pPage = FindPageFrm();
1386         if ( pPage )
1387         {
1388             if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
1389             {
1390                 //Das sollte er sein (kann allenfalls temporaer anders sein,
1391                 //                    sollte uns das beunruhigen?)
1392                 rInfo.SetInfo( pPage, this );
1393                 return sal_False;
1394             }
1395             if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
1396                  (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
1397             {
1398                 //Das koennte er sein.
1399                 rInfo.SetInfo( pPage, this );
1400             }
1401         }
1402     }
1403     return sal_True;
1404 }
1405 
1406 /*************************************************************************
1407  *                      SwTxtFrm::PrepWidows()
1408  *************************************************************************/
1409 
1410 void SwTxtFrm::PrepWidows( const MSHORT nNeed, sal_Bool bNotify )
1411 {
1412     ASSERT(GetFollow() && nNeed, "+SwTxtFrm::Prepare: lost all friends");
1413 
1414     SwParaPortion *pPara = GetPara();
1415     if ( !pPara )
1416         return;
1417     pPara->SetPrepWidows( sal_True );
1418 
1419     // These two lines of code have been deleted for #102340#.
1420     // Obviously the widow control does not work if we have a
1421     // pMaster->pFollow->pFollow situation:
1422 
1423     // returnen oder nicht ist hier die Frage.
1424     // Ohne IsLocked() ist 5156 gefaehrlich,
1425     // ohne IsFollow() werden die Orphans unterdrueckt: 6968.
1426     // Abfrage auf IsLocked erst hier, weil das Flag gesetzt werden soll.
1427 //  if( IsLocked() && IsFollow() )
1428 //      return;
1429 
1430     MSHORT nHave = nNeed;
1431 
1432     // Wir geben ein paar Zeilen ab und schrumpfen im CalcPreps()
1433     SWAP_IF_NOT_SWAPPED( this )
1434 
1435     SwTxtSizeInfo aInf( this );
1436     SwTxtMargin aLine( this, &aInf );
1437     aLine.Bottom();
1438     xub_StrLen nTmpLen = aLine.GetCurr()->GetLen();
1439     while( nHave && aLine.PrevLine() )
1440     {
1441         if( nTmpLen )
1442             --nHave;
1443         nTmpLen = aLine.GetCurr()->GetLen();
1444     }
1445     // In dieser Ecke tummelten sich einige Bugs: 7513, 7606.
1446     // Wenn feststeht, dass Zeilen abgegeben werden koennen,
1447     // muss der Master darueber hinaus die Widow-Regel ueberpruefen.
1448     if( !nHave )
1449     {
1450         sal_Bool bSplit;
1451         if( !IsFollow() )   //Nur ein Master entscheidet ueber Orphans
1452         {
1453             const WidowsAndOrphans aWidOrp( this );
1454             bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() &&
1455                        aLine.GetLineNr() >= aLine.GetDropLines() );
1456         }
1457         else
1458             bSplit = sal_True;
1459 
1460         if( bSplit )
1461         {
1462             GetFollow()->SetOfst( aLine.GetEnd() );
1463             aLine.TruncLines( sal_True );
1464             if( pPara->IsFollowField() )
1465                 GetFollow()->SetFieldFollow( sal_True );
1466         }
1467     }
1468     if ( bNotify )
1469     {
1470         _InvalidateSize();
1471         InvalidatePage();
1472     }
1473 
1474     UNDO_SWAP( this )
1475 }
1476 
1477 /*************************************************************************
1478  *                      SwTxtFrm::Prepare
1479  *************************************************************************/
1480 
1481 sal_Bool lcl_ErgoVadis( SwTxtFrm* pFrm, xub_StrLen &rPos, const PrepareHint ePrep )
1482 {
1483     const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1484     if( ePrep == PREP_ERGOSUM )
1485     {
1486         if( !rFtnInfo.aErgoSum.Len() )
1487             return sal_False;;
1488         rPos = pFrm->GetOfst();
1489     }
1490     else
1491     {
1492         if( !rFtnInfo.aQuoVadis.Len() )
1493             return sal_False;
1494         if( pFrm->HasFollow() )
1495             rPos = pFrm->GetFollow()->GetOfst();
1496         else
1497             rPos = pFrm->GetTxt().Len();
1498         if( rPos )
1499             --rPos; // unser letztes Zeichen
1500     }
1501     return sal_True;
1502 }
1503 
1504 void SwTxtFrm::Prepare( const PrepareHint ePrep, const void* pVoid,
1505                         sal_Bool bNotify )
1506 {
1507     SwFrmSwapper aSwapper( this, sal_False );
1508 
1509 #if OSL_DEBUG_LEVEL > 1
1510     const SwTwips nDbgY = Frm().Top();
1511     (void)nDbgY;
1512 #endif
1513 
1514     if ( IsEmpty() )
1515     {
1516         switch ( ePrep )
1517         {
1518             case PREP_BOSS_CHGD:
1519                 SetInvalidVert( sal_True );  // Test
1520             case PREP_WIDOWS_ORPHANS:
1521             case PREP_WIDOWS:
1522             case PREP_FTN_GONE :    return;
1523 
1524             case PREP_POS_CHGD :
1525             {
1526                 // Auch in (spaltigen) Bereichen ist ein InvalidateSize notwendig,
1527                 // damit formatiert wird und ggf. das bUndersized gesetzt wird.
1528                 if( IsInFly() || IsInSct() )
1529                 {
1530                     SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1531                         GetUpper()->Prt().Bottom();
1532                     if( nTmpBottom < Frm().Bottom() )
1533                         break;
1534                 }
1535                 // Gibt es ueberhaupt Flys auf der Seite ?
1536                 SwTxtFly aTxtFly( this );
1537                 if( aTxtFly.IsOn() )
1538                 {
1539                     // Ueberlappt irgendein Fly ?
1540                     aTxtFly.Relax();
1541                     if ( aTxtFly.IsOn() || IsUndersized() )
1542                         break;
1543                 }
1544                 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue())
1545                     break;
1546 
1547                 GETGRID( FindPageFrm() )
1548                 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1549                     break;
1550 
1551                 // --> OD 2004-07-16 #i28701# - consider anchored objects
1552                 if ( GetDrawObjs() )
1553                     break;
1554                 // <--
1555 
1556                 return;
1557             }
1558             default:
1559                 break;
1560         }
1561     }
1562 
1563     if( !HasPara() && PREP_MUST_FIT != ePrep )
1564     {
1565         SetInvalidVert( sal_True );  // Test
1566         ASSERT( !IsLocked(), "SwTxtFrm::Prepare: three of a perfect pair" );
1567         if ( bNotify )
1568             InvalidateSize();
1569         else
1570             _InvalidateSize();
1571         return;
1572     }
1573 
1574     //Objekt mit Locking aus dem Cache holen.
1575     SwTxtLineAccess aAccess( this );
1576     SwParaPortion *pPara = aAccess.GetPara();
1577 
1578     switch( ePrep )
1579     {
1580         case PREP_MOVEFTN :     Frm().Height(0);
1581                                 Prt().Height(0);
1582                                 _InvalidatePrt();
1583                                 _InvalidateSize();
1584                                 // KEIN break
1585         case PREP_ADJUST_FRM :  pPara->SetPrepAdjust( sal_True );
1586                                 if( IsFtnNumFrm() != pPara->IsFtnNum() ||
1587                                     IsUndersized() )
1588                                 {
1589                                     InvalidateRange( SwCharRange( 0, 1 ), 1);
1590                                     if( GetOfst() && !IsFollow() )
1591                                         _SetOfst( 0 );
1592                                 }
1593                                 break;
1594         case PREP_MUST_FIT :        pPara->SetPrepMustFit( sal_True );
1595             /* no break here */
1596         case PREP_WIDOWS_ORPHANS :  pPara->SetPrepAdjust( sal_True );
1597                                     break;
1598 
1599         case PREP_WIDOWS :
1600             // MustFit ist staerker als alles anderes
1601             if( pPara->IsPrepMustFit() )
1602                 return;
1603             // Siehe Kommentar in WidowsAndOrphans::FindOrphans und CalcPreps()
1604             PrepWidows( *(const MSHORT *)pVoid, bNotify );
1605             break;
1606 
1607         case PREP_FTN :
1608         {
1609             SwTxtFtn *pFtn = (SwTxtFtn *)pVoid;
1610             if( IsInFtn() )
1611             {
1612                 // Bin ich der erste TxtFrm einer Fussnote ?
1613                 if( !GetPrev() )
1614                     // Wir sind also ein TxtFrm der Fussnote, die
1615                     // die Fussnotenzahl zur Anzeige bringen muss.
1616                     // Oder den ErgoSum-Text...
1617                     InvalidateRange( SwCharRange( 0, 1 ), 1);
1618 
1619                 if( !GetNext() )
1620                 {
1621                     // Wir sind der letzte Ftn, jetzt muessten die
1622                     // QuoVadis-Texte geupdated werden.
1623                     const SwFtnInfo &rFtnInfo = GetNode()->GetDoc()->GetFtnInfo();
1624                     if( !pPara->UpdateQuoVadis( rFtnInfo.aQuoVadis ) )
1625                     {
1626                         xub_StrLen nPos = pPara->GetParLen();
1627                         if( nPos )
1628                             --nPos;
1629                         InvalidateRange( SwCharRange( nPos, 1 ), 1);
1630                     }
1631                 }
1632             }
1633             else
1634             {
1635                 // Wir sind also der TxtFrm _mit_ der Fussnote
1636                 const xub_StrLen nPos = *pFtn->GetStart();
1637                 InvalidateRange( SwCharRange( nPos, 1 ), 1);
1638             }
1639             break;
1640         }
1641         case PREP_BOSS_CHGD :
1642         {
1643     // Test
1644             {
1645                 SetInvalidVert( sal_False );
1646                 sal_Bool bOld = IsVertical();
1647                 SetInvalidVert( sal_True );
1648                 if( bOld != IsVertical() )
1649                     InvalidateRange( SwCharRange( GetOfst(), STRING_LEN ) );
1650             }
1651 
1652             if( HasFollow() )
1653             {
1654                 xub_StrLen nNxtOfst = GetFollow()->GetOfst();
1655                 if( nNxtOfst )
1656                     --nNxtOfst;
1657                 InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1);
1658             }
1659             if( IsInFtn() )
1660             {
1661                 xub_StrLen nPos;
1662                 if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) )
1663                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1664                 if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) )
1665                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1666             }
1667             // 4739: Wenn wir ein Seitennummernfeld besitzen, muessen wir
1668             // die Stellen invalidieren.
1669             SwpHints *pHints = GetTxtNode()->GetpSwpHints();
1670             if( pHints )
1671             {
1672                 const sal_uInt16 nSize = pHints->Count();
1673                 const xub_StrLen nEnd = GetFollow() ?
1674                                     GetFollow()->GetOfst() : STRING_LEN;
1675                 for ( sal_uInt16 i = 0; i < nSize; ++i )
1676                 {
1677                     const SwTxtAttr *pHt = (*pHints)[i];
1678                     const xub_StrLen nStart = *pHt->GetStart();
1679                     if( nStart >= GetOfst() )
1680                     {
1681                         if( nStart >= nEnd )
1682                             i = nSize;          // fuehrt das Ende herbei
1683                         else
1684                         {
1685                 // 4029: wenn wir zurueckfliessen und eine Ftn besitzen, so
1686                 // fliesst die Ftn in jedem Fall auch mit. Damit sie nicht im
1687                 // Weg steht, schicken wir uns ein ADJUST_FRM.
1688                 // pVoid != 0 bedeutet MoveBwd()
1689                             const MSHORT nWhich = pHt->Which();
1690                             if( RES_TXTATR_FIELD == nWhich ||
1691                                 (HasFtn() && pVoid && RES_TXTATR_FTN == nWhich))
1692                             InvalidateRange( SwCharRange( nStart, 1 ), 1 );
1693                         }
1694                     }
1695                 }
1696             }
1697             // A new boss, a new chance for growing
1698             if( IsUndersized() )
1699             {
1700                 _InvalidateSize();
1701                 InvalidateRange( SwCharRange( GetOfst(), 1 ), 1);
1702             }
1703             break;
1704         }
1705 
1706         case PREP_POS_CHGD :
1707         {
1708             if ( GetValidPrtAreaFlag() )
1709             {
1710                 GETGRID( FindPageFrm() )
1711                 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1712                     InvalidatePrt();
1713             }
1714 
1715             // Falls wir mit niemandem ueberlappen:
1716             // Ueberlappte irgendein Fly _vor_ der Positionsaenderung ?
1717             sal_Bool bFormat = pPara->HasFly();
1718             if( !bFormat )
1719             {
1720                 if( IsInFly() )
1721                 {
1722                     SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1723                         GetUpper()->Prt().Bottom();
1724                     if( nTmpBottom < Frm().Bottom() )
1725                         bFormat = sal_True;
1726                 }
1727                 if( !bFormat )
1728                 {
1729                     if ( GetDrawObjs() )
1730                     {
1731                         const sal_uInt32 nCnt = GetDrawObjs()->Count();
1732                         for ( MSHORT i = 0; i < nCnt; ++i )
1733                         {
1734                             SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
1735                             // --> OD 2004-07-16 #i28701# - consider all
1736                             // to-character anchored objects
1737                             if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
1738                                     == FLY_AT_CHAR )
1739                             {
1740                                 bFormat = sal_True;
1741                                 break;
1742                             }
1743                         }
1744                     }
1745                     if( !bFormat )
1746                     {
1747                         // Gibt es ueberhaupt Flys auf der Seite ?
1748                         SwTxtFly aTxtFly( this );
1749                         if( aTxtFly.IsOn() )
1750                         {
1751                             // Ueberlappt irgendein Fly ?
1752                             aTxtFly.Relax();
1753                             bFormat = aTxtFly.IsOn() || IsUndersized();
1754                         }
1755                     }
1756                 }
1757             }
1758 
1759             if( bFormat )
1760             {
1761                 if( !IsLocked() )
1762                 {
1763                     if( pPara->GetRepaint()->HasArea() )
1764                         SetCompletePaint();
1765                     Init();
1766                     pPara = 0;
1767                     _InvalidateSize();
1768                 }
1769             }
1770             else
1771             {
1772                 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1773                     Prepare( PREP_REGISTER, 0, bNotify );
1774                 // Durch Positionsverschiebungen mit Ftns muessen die
1775                 // Frames neu adjustiert werden.
1776                 else if( HasFtn() )
1777                 {
1778                     Prepare( PREP_ADJUST_FRM, 0, bNotify );
1779                     _InvalidateSize();
1780                 }
1781                 else
1782                     return;     // damit kein SetPrep() erfolgt.
1783             }
1784             break;
1785         }
1786         case PREP_REGISTER:
1787             if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1788             {
1789                 pPara->SetPrepAdjust( sal_True );
1790                 CalcLineSpace();
1791                 InvalidateSize();
1792                 _InvalidatePrt();
1793                 SwFrm* pNxt;
1794                 if ( 0 != ( pNxt = GetIndNext() ) )
1795                 {
1796                     pNxt->_InvalidatePrt();
1797                     if ( pNxt->IsLayoutFrm() )
1798                         pNxt->InvalidatePage();
1799                 }
1800                 SetCompletePaint();
1801             }
1802             break;
1803         case PREP_FTN_GONE :
1804             {
1805                 // Wenn ein Follow uns ruft, weil eine Fussnote geloescht wird, muss unsere
1806                 // letzte Zeile formatiert werden, damit ggf. die erste Zeile des Follows
1807                 // hochrutschen kann, die extra auf die naechste Seite gerutscht war, um mit
1808                 // der Fussnote zusammen zu sein, insbesondere bei spaltigen Bereichen.
1809                 ASSERT( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" );
1810                 xub_StrLen nPos = GetFollow()->GetOfst();
1811                 if( IsFollow() && GetOfst() == nPos )       // falls wir gar keine Textmasse besitzen,
1812                     FindMaster()->Prepare( PREP_FTN_GONE ); // rufen wir das Prepare unseres Masters
1813                 if( nPos )
1814                     --nPos; // das Zeichen vor unserem Follow
1815                 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1816                 return;
1817             }
1818         case PREP_ERGOSUM:
1819         case PREP_QUOVADIS:
1820             {
1821                 xub_StrLen nPos;
1822                 if( lcl_ErgoVadis( this, nPos, ePrep ) )
1823                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1824             }
1825             break;
1826         case PREP_FLY_ATTR_CHG:
1827         {
1828             if( pVoid )
1829             {
1830                 xub_StrLen nWhere = CalcFlyPos( (SwFrmFmt*)pVoid );
1831                 ASSERT( STRING_LEN != nWhere, "Prepare: Why me?" );
1832                 InvalidateRange( SwCharRange( nWhere, 1 ) );
1833                 return;
1834             }
1835             // else ... Laufe in den Default-Switch
1836         }
1837         case PREP_CLEAR:
1838         default:
1839         {
1840             if( IsLocked() )
1841             {
1842                 if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep )
1843                 {
1844                     xub_StrLen nLen = ( GetFollow() ? GetFollow()->GetOfst() :
1845                                       STRING_LEN ) - GetOfst();
1846                     InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 );
1847                 }
1848             }
1849             else
1850             {
1851                 if( pPara->GetRepaint()->HasArea() )
1852                     SetCompletePaint();
1853                 Init();
1854                 pPara = 0;
1855                 if( GetOfst() && !IsFollow() )
1856                     _SetOfst( 0 );
1857                 if ( bNotify )
1858                     InvalidateSize();
1859                 else
1860                     _InvalidateSize();
1861             }
1862             return;     // damit kein SetPrep() erfolgt.
1863         }
1864     }
1865     if( pPara )
1866         pPara->SetPrep( sal_True );
1867 }
1868 
1869 /* -----------------11.02.99 17:56-------------------
1870  * Kleine Hilfsklasse mit folgender Funktion:
1871  * Sie soll eine Probeformatierung vorbereiten.
1872  * Der Frame wird in Groesse und Position angepasst, sein SwParaPortion zur Seite
1873  * gestellt und eine neue erzeugt, dazu wird formatiert mit gesetztem bTestFormat.
1874  * Im Dtor wird der TxtFrm wieder in seinen alten Zustand zurueckversetzt.
1875  *
1876  * --------------------------------------------------*/
1877 
1878 class SwTestFormat
1879 {
1880     SwTxtFrm *pFrm;
1881     SwParaPortion *pOldPara;
1882     SwRect aOldFrm, aOldPrt;
1883 public:
1884     SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPrv, SwTwips nMaxHeight );
1885     ~SwTestFormat();
1886 };
1887 
1888 SwTestFormat::SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPre, SwTwips nMaxHeight )
1889     : pFrm( pTxtFrm )
1890 {
1891     aOldFrm = pFrm->Frm();
1892     aOldPrt = pFrm->Prt();
1893 
1894     SWRECTFN( pFrm )
1895     SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)();
1896 
1897     pFrm->Frm() = pFrm->GetUpper()->Prt();
1898     pFrm->Frm() += pFrm->GetUpper()->Frm().Pos();
1899 
1900     (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight );
1901     if( pFrm->GetPrev() )
1902         (pFrm->Frm().*fnRect->fnSetPosY)(
1903                 (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() -
1904                 ( bVert ? nMaxHeight + 1 : 0 ) );
1905 
1906     SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1907     const SwBorderAttrs &rAttrs = *aAccess.Get();
1908     (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) );
1909 
1910     if( pPre )
1911     {
1912         SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre );
1913         (pFrm->Prt().*fnRect->fnSetPosY)( nUpper );
1914     }
1915     (pFrm->Prt().*fnRect->fnSetHeight)(
1916         Max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() -
1917                   (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) );
1918     (pFrm->Prt().*fnRect->fnSetWidth)(
1919         (pFrm->Frm().*fnRect->fnGetWidth)() -
1920         // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
1921         ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) );
1922     pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL;
1923     pFrm->SetPara( new SwParaPortion(), sal_False );
1924 
1925     ASSERT( ! pFrm->IsSwapped(), "A frame is swapped before _Format" );
1926 
1927     if ( pFrm->IsVertical() )
1928         pFrm->SwapWidthAndHeight();
1929 
1930     SwTxtFormatInfo aInf( pFrm, sal_False, sal_True, sal_True );
1931     SwTxtFormatter  aLine( pFrm, &aInf );
1932 
1933     pFrm->_Format( aLine, aInf );
1934 
1935     if ( pFrm->IsVertical() )
1936         pFrm->SwapWidthAndHeight();
1937 
1938     ASSERT( ! pFrm->IsSwapped(), "A frame is swapped after _Format" );
1939 }
1940 
1941 SwTestFormat::~SwTestFormat()
1942 {
1943     pFrm->Frm() = aOldFrm;
1944     pFrm->Prt() = aOldPrt;
1945     pFrm->SetPara( pOldPara );
1946 }
1947 
1948 sal_Bool SwTxtFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, sal_Bool &bSplit )
1949 {
1950     PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 )
1951 
1952     if( IsLocked() && GetUpper()->Prt().Width() <= 0 )
1953         return sal_False;
1954 
1955     SwTestFormat aSave( this, pPrv, rMaxHeight );
1956 
1957     return SwTxtFrm::WouldFit( rMaxHeight, bSplit, sal_True );
1958 }
1959 
1960 
1961 /*************************************************************************
1962  *                      SwTxtFrm::WouldFit()
1963  *************************************************************************/
1964 
1965 /* SwTxtFrm::WouldFit()
1966  * sal_True: wenn ich aufspalten kann.
1967  * Es soll und braucht nicht neu formatiert werden.
1968  * Wir gehen davon aus, dass bereits formatiert wurde und dass
1969  * die Formatierungsdaten noch aktuell sind.
1970  * Wir gehen davon aus, dass die Framebreiten des evtl. Masters und
1971  * Follows gleich sind. Deswegen wird kein FindBreak() mit FindOrphans()
1972  * gerufen.
1973  * Die benoetigte Hoehe wird von nMaxHeight abgezogen!
1974  */
1975 
1976 sal_Bool SwTxtFrm::WouldFit( SwTwips &rMaxHeight, sal_Bool &bSplit, sal_Bool bTst )
1977 {
1978     ASSERT( ! IsVertical() || ! IsSwapped(),
1979             "SwTxtFrm::WouldFit with swapped frame" );
1980     SWRECTFN( this );
1981 
1982     if( IsLocked() )
1983         return sal_False;
1984 
1985     //Kann gut sein, dass mir der IdleCollector mir die gecachten
1986     //Informationen entzogen hat.
1987     if( !IsEmpty() )
1988         GetFormatted();
1989 
1990     // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph
1991     // can *not* be applied, if test format is in progress. The test format doesn't
1992     // adjust the frame and the printing area - see method <SwTxtFrm::_Format(..)>,
1993     // which is called in <SwTxtFrm::TestFormat(..)>
1994     if ( IsEmpty() && !bTst )
1995     {
1996         bSplit = sal_False;
1997         SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height();
1998         if( rMaxHeight < nHeight )
1999             return sal_False;
2000         else
2001         {
2002             rMaxHeight -= nHeight;
2003             return sal_True;
2004         }
2005     }
2006 
2007     // In sehr unguenstigen Faellen kann GetPara immer noch 0 sein.
2008     // Dann returnen wir sal_True, um auf der neuen Seite noch einmal
2009     // anformatiert zu werden.
2010     ASSERT( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" );
2011     if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) )
2012         return sal_True;
2013 
2014     // Da das Orphan-Flag nur sehr fluechtig existiert, wird als zweite
2015     // Bedingung  ueberprueft, ob die Rahmengroesse durch CalcPreps
2016     // auf riesengross gesetzt wird, um ein MoveFwd zu erzwingen.
2017     if( IsWidow() || ( bVert ?
2018                        ( 0 == Frm().Left() ) :
2019                        ( LONG_MAX - 20000 < Frm().Bottom() ) ) )
2020     {
2021         SetWidow(sal_False);
2022         if ( GetFollow() )
2023         {
2024             // Wenn wir hier durch eine Widow-Anforderung unseres Follows gelandet
2025             // sind, wird ueberprueft, ob es ueberhaupt einen Follow mit einer
2026             // echten Hoehe gibt, andernfalls (z.B. in neu angelegten SctFrms)
2027             // ignorieren wir das IsWidow() und pruefen doch noch, ob wir
2028             // genung Platz finden.
2029             if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) ||
2030                   (   bVert && 0 < Frm().Left() ) ) &&
2031                   ( GetFollow()->IsVertical() ?
2032                     !GetFollow()->Frm().Width() :
2033                     !GetFollow()->Frm().Height() ) )
2034             {
2035                 SwTxtFrm* pFoll = GetFollow()->GetFollow();
2036                 while( pFoll &&
2037                         ( pFoll->IsVertical() ?
2038                          !pFoll->Frm().Width() :
2039                          !pFoll->Frm().Height() ) )
2040                     pFoll = pFoll->GetFollow();
2041                 if( pFoll )
2042                     return sal_False;
2043             }
2044             else
2045                 return sal_False;
2046         }
2047     }
2048 
2049     SWAP_IF_NOT_SWAPPED( this );
2050 
2051     SwTxtSizeInfo aInf( this );
2052     SwTxtMargin aLine( this, &aInf );
2053 
2054     WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit );
2055 
2056     sal_Bool bRet = sal_True;
2057 
2058     aLine.Bottom();
2059     // Ist Aufspalten ueberhaupt notwendig?
2060     if ( 0 != ( bSplit = !aFrmBreak.IsInside( aLine ) ) )
2061         bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst );
2062     else
2063     {
2064         //Wir brauchen die Gesamthoehe inklusive der aktuellen Zeile
2065         aLine.Top();
2066         do
2067         {
2068             rMaxHeight -= aLine.GetLineHeight();
2069         } while ( aLine.Next() );
2070     }
2071 
2072     UNDO_SWAP( this )
2073 
2074     return bRet;
2075 }
2076 
2077 
2078 /*************************************************************************
2079  *                      SwTxtFrm::GetParHeight()
2080  *************************************************************************/
2081 
2082 KSHORT SwTxtFrm::GetParHeight() const
2083 {
2084     ASSERT( ! IsVertical() || ! IsSwapped(),
2085             "SwTxtFrm::GetParHeight with swapped frame" )
2086 
2087     if( !HasPara() )
2088     {   // Fuer nichtleere Absaetze ist dies ein Sonderfall, da koennen wir
2089         // bei UnderSized ruhig nur 1 Twip mehr anfordern.
2090         KSHORT nRet = (KSHORT)Prt().SSize().Height();
2091         if( IsUndersized() )
2092         {
2093             if( IsEmpty() )
2094                 nRet = (KSHORT)EmptyHeight();
2095             else
2096                 ++nRet;
2097         }
2098         return nRet;
2099     }
2100 
2101     // FME, OD 08.01.2004 #i11859# - refactoring and improve code
2102     const SwLineLayout* pLineLayout = GetPara();
2103     KSHORT nHeight = pLineLayout->GetRealHeight();
2104     if( GetOfst() && !IsFollow() )  // Ist dieser Absatz gescrollt? Dann ist unsere
2105         nHeight *= 2;               // bisherige Hoehe mind. eine Zeilenhoehe zu gering
2106     // OD 2004-03-04 #115793#
2107     while ( pLineLayout && pLineLayout->GetNext() )
2108     {
2109         pLineLayout = pLineLayout->GetNext();
2110         nHeight = nHeight + pLineLayout->GetRealHeight();
2111     }
2112 
2113     return nHeight;
2114 }
2115 
2116 
2117 /*************************************************************************
2118  *                      SwTxtFrm::GetFormatted()
2119  *************************************************************************/
2120 
2121 // returnt this _immer_ im formatierten Zustand!
2122 SwTxtFrm* SwTxtFrm::GetFormatted( bool bForceQuickFormat )
2123 {
2124     SWAP_IF_SWAPPED( this )
2125 
2126     //Kann gut sein, dass mir der IdleCollector mir die gecachten
2127     //Informationen entzogen hat. Calc() ruft unser Format.
2128                       //Nicht bei leeren Absaetzen!
2129     if( !HasPara() && !(IsValid() && IsEmpty()) )
2130     {
2131         // Calc() muss gerufen werden, weil unsere Frameposition
2132         // nicht stimmen muss.
2133         const sal_Bool bFormat = GetValidSizeFlag();
2134         Calc();
2135         // Es kann durchaus sein, dass Calc() das Format()
2136         // nicht anstiess (weil wir einst vom Idle-Zerstoerer
2137         // aufgefordert wurden unsere Formatinformationen wegzuschmeissen).
2138         // 6995: Optimierung mit FormatQuick()
2139         if( bFormat && !FormatQuick( bForceQuickFormat ) )
2140             Format();
2141     }
2142 
2143     UNDO_SWAP( this )
2144 
2145     return this;
2146 }
2147 
2148 /*************************************************************************
2149  *                      SwTxtFrm::CalcFitToContent()
2150  *************************************************************************/
2151 
2152 SwTwips SwTxtFrm::CalcFitToContent()
2153 {
2154     // --> FME 2004-07-16 #i31490#
2155     // If we are currently locked, we better return with a
2156     // fairly reasonable value:
2157     if ( IsLocked() )
2158         return Prt().Width();
2159     // <--
2160 
2161     SwParaPortion* pOldPara = GetPara();
2162     SwParaPortion *pDummy = new SwParaPortion();
2163     SetPara( pDummy, false );
2164     const SwPageFrm* pPage = FindPageFrm();
2165 
2166     const Point   aOldFrmPos   = Frm().Pos();
2167     const SwTwips nOldFrmWidth = Frm().Width();
2168     const SwTwips nOldPrtWidth = Prt().Width();
2169     const SwTwips nPageWidth = GetUpper()->IsVertical() ?
2170                                pPage->Prt().Height() :
2171                                pPage->Prt().Width();
2172 
2173     Frm().Width( nPageWidth );
2174     Prt().Width( nPageWidth );
2175 
2176     // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2177     if ( IsRightToLeft() )
2178         Frm().Pos().X() += nOldFrmWidth - nPageWidth;
2179 
2180     // --> FME 2004-07-16 #i31490#
2181     SwTxtFrmLocker aLock( this );
2182     // <--
2183 
2184     SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2185     aInf.SetIgnoreFly( sal_True );
2186     SwTxtFormatter  aLine( this, &aInf );
2187     SwHookOut aHook( aInf );
2188 
2189     // --> OD 2005-09-06 #i54031# - assure mininum of MINLAY twips.
2190     const SwTwips nMax = Max( (SwTwips)MINLAY,
2191                               aLine._CalcFitToContent() + 1 );
2192     // <--
2193 
2194     Frm().Width( nOldFrmWidth );
2195     Prt().Width( nOldPrtWidth );
2196 
2197     // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2198     if ( IsRightToLeft() )
2199         Frm().Pos() = aOldFrmPos;
2200 
2201 
2202     SetPara( pOldPara );
2203 
2204     return nMax;
2205 }
2206 
2207 /** simulate format for a list item paragraph, whose list level attributes
2208     are in LABEL_ALIGNMENT mode, in order to determine additional first
2209     line offset for the real text formatting due to the value of label
2210     adjustment attribute of the list level.
2211 
2212     OD 2008-01-31 #newlistlevelattrs#
2213 
2214     @author OD
2215 */
2216 void SwTxtFrm::CalcAdditionalFirstLineOffset()
2217 {
2218     if ( IsLocked() )
2219         return;
2220 
2221     // reset additional first line offset
2222     mnAdditionalFirstLineOffset = 0;
2223 
2224     const SwTxtNode* pTxtNode( GetTxtNode() );
2225     if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->IsCountedInList() &&
2226          pTxtNode->GetNumRule() )
2227     {
2228         const SwNumFmt& rNumFmt =
2229                 pTxtNode->GetNumRule()->Get( static_cast<sal_uInt16>(pTxtNode->GetActualListLevel()) );
2230         if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2231         {
2232             // keep current paragraph portion and apply dummy paragraph portion
2233             SwParaPortion* pOldPara = GetPara();
2234             SwParaPortion *pDummy = new SwParaPortion();
2235             SetPara( pDummy, false );
2236 
2237             // lock paragraph
2238             SwTxtFrmLocker aLock( this );
2239 
2240             // simulate text formatting
2241             SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2242             aInf.SetIgnoreFly( sal_True );
2243             SwTxtFormatter aLine( this, &aInf );
2244             SwHookOut aHook( aInf );
2245             aLine._CalcFitToContent();
2246 
2247             // determine additional first line offset
2248             const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion();
2249             if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFtnNumPortion() )
2250             {
2251                 SwTwips nNumberPortionWidth( pFirstPortion->Width() );
2252 
2253                 const SwLinePortion* pPortion = pFirstPortion->GetPortion();
2254                 while ( pPortion &&
2255                         pPortion->InNumberGrp() && !pPortion->IsFtnNumPortion())
2256                 {
2257                     nNumberPortionWidth += pPortion->Width();
2258                     pPortion = pPortion->GetPortion();
2259                 }
2260 
2261                 if ( ( IsRightToLeft() &&
2262                        rNumFmt.GetNumAdjust() == SVX_ADJUST_LEFT ) ||
2263                      ( !IsRightToLeft() &&
2264                        rNumFmt.GetNumAdjust() == SVX_ADJUST_RIGHT ) )
2265                 {
2266                     mnAdditionalFirstLineOffset = -nNumberPortionWidth;
2267                 }
2268                 else if ( rNumFmt.GetNumAdjust() == SVX_ADJUST_CENTER )
2269                 {
2270                     mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2);
2271                 }
2272             }
2273 
2274             // restore paragraph portion
2275             SetPara( pOldPara );
2276         }
2277     }
2278 }
2279 
2280 /** determine height of last line for the calculation of the proportional line
2281     spacing
2282 
2283     OD 08.01.2004 #i11859#
2284     OD 2004-03-17 #i11860# - method <GetHeightOfLastLineForPropLineSpacing()>
2285     replace by method <_CalcHeightOfLastLine()>. Height of last line will be
2286     stored in new member <mnHeightOfLastLine> and can be accessed via method
2287     <GetHeightOfLastLine()>
2288     OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont>
2289     in order to force the usage of the former algorithm to determine the
2290     height of the last line, which uses the font.
2291 
2292     @author OD
2293 */
2294 void SwTxtFrm::_CalcHeightOfLastLine( const bool _bUseFont )
2295 {
2296     // --> OD 2006-11-13 #i71281#
2297     // invalidate printing area, if height of last line changes
2298     const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine );
2299     // <--
2300     // determine output device
2301     ViewShell* pVsh = getRootFrm()->GetCurrShell();
2302     ASSERT( pVsh, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no ViewShell" );
2303     // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2304     // There could be no <ViewShell> instance in the case of loading a binary
2305     // StarOffice file format containing an embedded Writer document.
2306     if ( !pVsh )
2307     {
2308         return;
2309     }
2310     OutputDevice* pOut = pVsh->GetOut();
2311     const IDocumentSettingAccess* pIDSA = GetTxtNode()->getIDocumentSettingAccess();
2312     if ( !pVsh->GetViewOptions()->getBrowseMode() ||
2313           pVsh->GetViewOptions()->IsPrtFormat() )
2314     {
2315         pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
2316     }
2317     ASSERT( pOut, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no OutputDevice" );
2318     // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2319     if ( !pOut )
2320     {
2321         return;
2322     }
2323     // <--
2324 
2325     // determine height of last line
2326 
2327     if ( _bUseFont || pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING ) )
2328     {
2329         // former determination of last line height for proprotional line
2330         // spacing - take height of font set at the paragraph
2331         SwFont aFont( GetAttrSet(), pIDSA );
2332 
2333         // Wir muessen dafuer sorgen, dass am OutputDevice der Font
2334         // korrekt restauriert wird, sonst droht ein Last!=Owner.
2335         if ( pLastFont )
2336         {
2337             SwFntObj *pOldFont = pLastFont;
2338             pLastFont = NULL;
2339             aFont.SetFntChg( sal_True );
2340             aFont.ChgPhysFnt( pVsh, *pOut );
2341             mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2342             pLastFont->Unlock();
2343             pLastFont = pOldFont;
2344             pLastFont->SetDevFont( pVsh, *pOut );
2345         }
2346         else
2347         {
2348             Font aOldFont = pOut->GetFont();
2349             aFont.SetFntChg( sal_True );
2350             aFont.ChgPhysFnt( pVsh, *pOut );
2351             mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2352             pLastFont->Unlock();
2353             pLastFont = NULL;
2354             pOut->SetFont( aOldFont );
2355         }
2356     }
2357     else
2358     {
2359         // new determination of last line height - take actually height of last line
2360         // --> OD 2008-05-06 #i89000#
2361         // assure same results, if paragraph is undersized
2362         if ( IsUndersized() )
2363         {
2364             mnHeightOfLastLine = 0;
2365         }
2366         else
2367         {
2368             bool bCalcHeightOfLastLine = true;
2369             if ( !HasPara() )
2370             {
2371                 if ( IsEmpty() )
2372                 {
2373                     mnHeightOfLastLine = EmptyHeight();
2374                     bCalcHeightOfLastLine = false;
2375                 }
2376             }
2377 
2378             if ( bCalcHeightOfLastLine )
2379             {
2380                 ASSERT( HasPara(),
2381                         "<SwTxtFrm::_CalcHeightOfLastLine()> - missing paragraph portions." );
2382                 const SwLineLayout* pLineLayout = GetPara();
2383                 while ( pLineLayout && pLineLayout->GetNext() )
2384                 {
2385                     // iteration to last line
2386                     pLineLayout = pLineLayout->GetNext();
2387                 }
2388                 if ( pLineLayout )
2389                 {
2390                     SwTwips nAscent, nDescent, nDummy1, nDummy2;
2391                     // --> OD 2005-05-20 #i47162# - suppress consideration of
2392                     // fly content portions and the line portion.
2393                     pLineLayout->MaxAscentDescent( nAscent, nDescent,
2394                                                    nDummy1, nDummy2,
2395                                                    0, true );
2396                     // <--
2397                     // --> OD 2006-11-22 #i71281#
2398                     // Suppress wrong invalidation of printing area, if method is
2399                     // called recursive.
2400                     // Thus, member <mnHeightOfLastLine> is only set directly, if
2401                     // no recursive call is needed.
2402     //                mnHeightOfLastLine = nAscent + nDescent;
2403                     const SwTwips nNewHeightOfLastLine = nAscent + nDescent;
2404                     // --> OD 2005-05-20 #i47162# - if last line only contains
2405                     // fly content portions, <mnHeightOfLastLine> is zero.
2406                     // In this case determine height of last line by the font
2407                     if ( nNewHeightOfLastLine == 0 )
2408                     {
2409                         _CalcHeightOfLastLine( true );
2410                     }
2411                     else
2412                     {
2413                         mnHeightOfLastLine = nNewHeightOfLastLine;
2414                     }
2415                     // <--
2416                     // <--
2417                 }
2418             }
2419         }
2420         // <--
2421     }
2422     // --> OD 2006-11-13 #i71281#
2423     // invalidate printing area, if height of last line changes
2424     if ( mnHeightOfLastLine != mnOldHeightOfLastLine )
2425     {
2426         InvalidatePrt();
2427     }
2428     // <--
2429 }
2430 
2431 /*************************************************************************
2432  *                      SwTxtFrm::GetLineSpace()
2433  *************************************************************************/
2434 // OD 07.01.2004 #i11859# - change return data type
2435 //      add default parameter <_bNoPropLineSpacing> to control, if the
2436 //      value of a proportional line spacing is returned or not
2437 // OD 07.01.2004 - trying to describe purpose of method:
2438 //      Method returns the value of the inter line spacing for a text frame.
2439 //      Such a value exists for proportional line spacings ("1,5 Lines",
2440 //      "Double", "Proportional" and for leading line spacing ("Leading").
2441 //      By parameter <_bNoPropLineSpace> (default value false) it can be
2442 //      controlled, if the value of a proportional line spacing is returned.
2443 long SwTxtFrm::GetLineSpace( const bool _bNoPropLineSpace ) const
2444 {
2445     long nRet = 0;
2446 
2447     const SwAttrSet* pSet = GetAttrSet();
2448     const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
2449 
2450     switch( rSpace.GetInterLineSpaceRule() )
2451     {
2452         case SVX_INTER_LINE_SPACE_PROP:
2453         {
2454             // OD 07.01.2004 #i11859#
2455             if ( _bNoPropLineSpace )
2456             {
2457                 break;
2458             }
2459 
2460             // OD 2004-03-17 #i11860# - use method <GetHeightOfLastLine()>
2461             nRet = GetHeightOfLastLine();
2462 
2463             long nTmp = nRet;
2464             nTmp *= rSpace.GetPropLineSpace();
2465             nTmp /= 100;
2466             nTmp -= nRet;
2467             if ( nTmp > 0 )
2468                 nRet = nTmp;
2469             else
2470                 nRet = 0;
2471         }
2472             break;
2473         case SVX_INTER_LINE_SPACE_FIX:
2474         {
2475             if ( rSpace.GetInterLineSpace() > 0 )
2476                 nRet = rSpace.GetInterLineSpace();
2477         }
2478             break;
2479         default:
2480             break;
2481     }
2482     return nRet;
2483 }
2484 
2485 /*************************************************************************
2486  *                      SwTxtFrm::FirstLineHeight()
2487  *************************************************************************/
2488 
2489 KSHORT SwTxtFrm::FirstLineHeight() const
2490 {
2491     if ( !HasPara() )
2492     {
2493         if( IsEmpty() && IsValid() )
2494             return IsVertical() ? (KSHORT)Prt().Width() : (KSHORT)Prt().Height();
2495         return KSHRT_MAX;
2496     }
2497     const SwParaPortion *pPara = GetPara();
2498     if ( !pPara )
2499         return KSHRT_MAX;
2500 
2501     return pPara->Height();
2502 }
2503 
2504 MSHORT SwTxtFrm::GetLineCount( xub_StrLen nPos )
2505 {
2506     MSHORT nRet = 0;
2507     SwTxtFrm *pFrm = this;
2508     do
2509     {
2510         pFrm->GetFormatted();
2511         if( !pFrm->HasPara() )
2512             break;
2513         SwTxtSizeInfo aInf( pFrm );
2514         SwTxtMargin aLine( pFrm, &aInf );
2515         if( STRING_LEN == nPos )
2516             aLine.Bottom();
2517         else
2518             aLine.CharToLine( nPos );
2519         nRet = nRet + aLine.GetLineNr();
2520         pFrm = pFrm->GetFollow();
2521     } while ( pFrm && pFrm->GetOfst() <= nPos );
2522     return nRet;
2523 }
2524 
2525 void SwTxtFrm::ChgThisLines()
2526 {
2527     //not necassary to format here (GerFormatted etc.), because we have to come from there!
2528 
2529     sal_uLong nNew = 0;
2530     const SwLineNumberInfo &rInf = GetNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo();
2531     if ( GetTxt().Len() && HasPara() )
2532     {
2533         SwTxtSizeInfo aInf( this );
2534         SwTxtMargin aLine( this, &aInf );
2535         if ( rInf.IsCountBlankLines() )
2536         {
2537             aLine.Bottom();
2538             nNew = (sal_uLong)aLine.GetLineNr();
2539         }
2540         else
2541         {
2542             do
2543             {
2544                 if( aLine.GetCurr()->HasCntnt() )
2545                     ++nNew;
2546             } while ( aLine.NextLine() );
2547         }
2548     }
2549     else if ( rInf.IsCountBlankLines() )
2550         nNew = 1;
2551 
2552     if ( nNew != nThisLines )
2553     {
2554         if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
2555         {
2556             nAllLines -= nThisLines;
2557             nThisLines = nNew;
2558             nAllLines  += nThisLines;
2559             SwFrm *pNxt = GetNextCntntFrm();
2560             while( pNxt && pNxt->IsInTab() )
2561             {
2562                 if( 0 != (pNxt = pNxt->FindTabFrm()) )
2563                     pNxt = pNxt->FindNextCnt();
2564             }
2565             if( pNxt )
2566                 pNxt->InvalidateLineNum();
2567 
2568             //Extend repaint to the bottom.
2569             if ( HasPara() )
2570             {
2571                 SwRepaint *pRepaint = GetPara()->GetRepaint();
2572                 pRepaint->Bottom( Max( pRepaint->Bottom(),
2573                                        Frm().Top()+Prt().Bottom()));
2574             }
2575         }
2576         else //Paragraphs which are not counted should not manipulate the AllLines.
2577             nThisLines = nNew;
2578     }
2579 
2580     //mba: invalidating is not necessary; if mongolian script has a problem, it should be fixed at the ritgh place
2581     //with invalidating we probably get too much flickering
2582     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
2583     //Ugly. How can we hack if better?
2584     //InvalidatePage();
2585 }
2586 
2587 
2588 void SwTxtFrm::RecalcAllLines()
2589 {
2590     ValidateLineNum();
2591 
2592     const SwAttrSet *pAttrSet = GetAttrSet();
2593 
2594     if ( !IsInTab() )
2595     {
2596         const sal_uLong nOld = GetAllLines();
2597         const SwFmtLineNumber &rLineNum = pAttrSet->GetLineNumber();
2598         sal_uLong nNewNum;
2599         const bool bRestart = GetTxtNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo().IsRestartEachPage();
2600 
2601         if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() )
2602             nNewNum = rLineNum.GetStartValue() - 1;
2603         //If it is a follow or not has not be considered if it is a restart at each page; the
2604         //restart should also take affekt at follows.
2605         else if ( bRestart && FindPageFrm()->FindFirstBodyCntnt() == this )
2606         {
2607             nNewNum = 0;
2608         }
2609         else
2610         {
2611             SwCntntFrm *pPrv = GetPrevCntntFrm();
2612             while ( pPrv &&
2613                     (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) )
2614                 pPrv = pPrv->GetPrevCntntFrm();
2615 
2616             // --> FME 2007-06-22 #i78254# Restart line numbering at page change:
2617             // First body content may be in table!
2618             if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() )
2619                 pPrv = 0;
2620             // <--
2621 
2622             nNewNum = pPrv ? ((SwTxtFrm*)pPrv)->GetAllLines() : 0;
2623         }
2624         if ( rLineNum.IsCount() )
2625             nNewNum += GetThisLines();
2626 
2627         if ( nOld != nNewNum )
2628         {
2629             nAllLines = nNewNum;
2630             SwCntntFrm *pNxt = GetNextCntntFrm();
2631             while ( pNxt &&
2632                     (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) )
2633                 pNxt = pNxt->GetNextCntntFrm();
2634             if ( pNxt )
2635             {
2636                 if ( pNxt->GetUpper() != GetUpper() )
2637                     pNxt->InvalidateLineNum();
2638                 else
2639                     pNxt->_InvalidateLineNum();
2640             }
2641         }
2642     }
2643 }
2644 
2645 void SwTxtFrm::VisitPortions( SwPortionHandler& rPH ) const
2646 {
2647     const SwParaPortion* pPara = GetPara();
2648 
2649     if( pPara )
2650     {
2651         if ( IsFollow() )
2652             rPH.Skip( GetOfst() );
2653 
2654         const SwLineLayout* pLine = pPara;
2655         while ( pLine )
2656         {
2657             const SwLinePortion* pPor = pLine->GetFirstPortion();
2658             while ( pPor )
2659             {
2660                 pPor->HandlePortion( rPH );
2661                 pPor = pPor->GetPortion();
2662             }
2663 
2664             rPH.LineBreak();
2665             pLine = pLine->GetNext();
2666         }
2667     }
2668 
2669     rPH.Finish();
2670 }
2671 
2672 
2673 /*************************************************************************
2674  *                      SwTxtFrm::GetScriptInfo()
2675  *************************************************************************/
2676 
2677 const SwScriptInfo* SwTxtFrm::GetScriptInfo() const
2678 {
2679     const SwParaPortion* pPara = GetPara();
2680     return pPara ? &pPara->GetScriptInfo() : 0;
2681 }
2682 
2683 /*************************************************************************
2684  *                      lcl_CalcFlyBasePos()
2685  * Helper function for SwTxtFrm::CalcBasePosForFly()
2686  *************************************************************************/
2687 
2688 SwTwips lcl_CalcFlyBasePos( const SwTxtFrm& rFrm, SwRect aFlyRect,
2689                             SwTxtFly& rTxtFly )
2690 {
2691     SWRECTFN( (&rFrm) )
2692     SwTwips nRet = rFrm.IsRightToLeft() ?
2693                    (rFrm.Frm().*fnRect->fnGetRight)() :
2694                    (rFrm.Frm().*fnRect->fnGetLeft)();
2695 
2696     do
2697     {
2698         SwRect aRect = rTxtFly.GetFrm( aFlyRect );
2699         if ( 0 != (aRect.*fnRect->fnGetWidth)() )
2700         {
2701             if ( rFrm.IsRightToLeft() )
2702             {
2703                 if ( (aRect.*fnRect->fnGetRight)() -
2704                      (aFlyRect.*fnRect->fnGetRight)() >= 0 )
2705                 {
2706                     (aFlyRect.*fnRect->fnSetRight)(
2707                         (aRect.*fnRect->fnGetLeft)() );
2708                     nRet = (aRect.*fnRect->fnGetLeft)();
2709                 }
2710                 else
2711                     break;
2712             }
2713             else
2714             {
2715                 if ( (aFlyRect.*fnRect->fnGetLeft)() -
2716                      (aRect.*fnRect->fnGetLeft)() >= 0 )
2717                 {
2718                     (aFlyRect.*fnRect->fnSetLeft)(
2719                         (aRect.*fnRect->fnGetRight)() + 1 );
2720                     nRet = (aRect.*fnRect->fnGetRight)();
2721                 }
2722                 else
2723                     break;
2724             }
2725         }
2726         else
2727             break;
2728     }
2729     while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 );
2730 
2731     return nRet;
2732 }
2733 
2734 /*************************************************************************
2735  *                      SwTxtFrm::CalcBasePosForFly()
2736  *************************************************************************/
2737 
2738 void SwTxtFrm::CalcBaseOfstForFly()
2739 {
2740     ASSERT( !IsVertical() || !IsSwapped(),
2741             "SwTxtFrm::CalcBasePosForFly with swapped frame!" )
2742 
2743     const SwNode* pNode = GetTxtNode();
2744     if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_FLY_OFFSETS) )
2745         return;
2746 
2747     SWRECTFN( this )
2748 
2749     SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() );
2750 
2751     // Get first 'real' line and adjust position and height of line rectangle
2752     // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour,
2753     // if no 'real' line exists (empty paragraph with and without a dummy portion)
2754     {
2755         SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)();
2756         const SwLineLayout* pLay = GetPara();
2757         SwTwips nLineHeight = 200;
2758         while( pLay && pLay->IsDummy() && pLay->GetNext() )
2759         {
2760             nTop += pLay->Height();
2761             pLay = pLay->GetNext();
2762         }
2763         if ( pLay )
2764         {
2765             nLineHeight = pLay->Height();
2766         }
2767         (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight );
2768     }
2769 
2770     SwTxtFly aTxtFly( this );
2771     aTxtFly.SetIgnoreCurrentFrame( sal_True );
2772     aTxtFly.SetIgnoreContour( sal_True );
2773     // --> OD 2004-12-17 #118809# - ignore objects in page header|footer for
2774     // text frames not in page header|footer
2775     aTxtFly.SetIgnoreObjsInHeaderFooter( sal_True );
2776     // <--
2777     SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2778     aTxtFly.SetIgnoreCurrentFrame( sal_False );
2779     SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2780 
2781     // make values relative to frame start position
2782     SwTwips nLeft = IsRightToLeft() ?
2783                     (Frm().*fnRect->fnGetRight)() :
2784                     (Frm().*fnRect->fnGetLeft)();
2785 
2786     mnFlyAnchorOfst = nRet1 - nLeft;
2787     mnFlyAnchorOfstNoWrap = nRet2 - nLeft;
2788 }
2789 
2790 /* repaint all text frames of the given text node */
2791 void SwTxtFrm::repaintTextFrames( const SwTxtNode& rNode )
2792 {
2793     SwIterator<SwTxtFrm,SwTxtNode> aIter( rNode );
2794     for( const SwTxtFrm *pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
2795     {
2796         SwRect aRec( pFrm->PaintArea() );
2797         const SwRootFrm *pRootFrm = pFrm->getRootFrm();
2798         ViewShell *pCurShell = pRootFrm ? pRootFrm->GetCurrShell() : NULL;
2799         if( pCurShell )
2800             pCurShell->InvalidateWindows( aRec );
2801     }
2802 }
2803 
2804