xref: /AOO41X/main/sw/source/core/text/txtfrm.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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 /* Seit dem neuen Blocksatz muessen wir immer neu formatieren:
1335         case RES_PARATR_ADJUST:
1336         {
1337             if( GetShell() )
1338             {
1339                 Prepare( PREP_CLEAR );
1340             }
1341             break;
1342         }
1343 */
1344         // 6870: SwDocPosUpdate auswerten.
1345         case RES_DOCPOS_UPDATE:
1346         {
1347             if( pOld && pNew )
1348             {
1349                 const SwDocPosUpdate *pDocPos = (const SwDocPosUpdate*)pOld;
1350                 if( pDocPos->nDocPos <= aFrm.Top() )
1351                 {
1352                     const SwFmtFld *pFld = (const SwFmtFld *)pNew;
1353                     InvalidateRange(
1354                         SwCharRange( *pFld->GetTxtFld()->GetStart(), 1 ) );
1355                 }
1356             }
1357             break;
1358         }
1359         case RES_PARATR_SPLIT:
1360             if ( GetPrev() )
1361                 CheckKeep();
1362             Prepare( PREP_CLEAR );
1363             bSetFldsDirty = sal_True;
1364             break;
1365         case RES_FRAMEDIR :
1366             SetDerivedR2L( sal_False );
1367             CheckDirChange();
1368             break;
1369         default:
1370         {
1371             Prepare( PREP_CLEAR );
1372             _InvalidatePrt();
1373             if ( !nWhich )
1374             {
1375                 //Wird z.B. bei HiddenPara mit 0 gerufen.
1376                 SwFrm *pNxt;
1377                 if ( 0 != (pNxt = FindNext()) )
1378                     pNxt->InvalidatePrt();
1379             }
1380         }
1381     } // switch
1382 
1383     if( bSetFldsDirty )
1384         GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( sal_True, GetNode(), 1 );
1385 
1386     if ( bRecalcFtnFlag )
1387         CalcFtnFlag();
1388 }
1389 
1390 sal_Bool SwTxtFrm::GetInfo( SfxPoolItem &rHnt ) const
1391 {
1392     if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && ! IsFollow() )
1393     {
1394         SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
1395         const SwPageFrm *pPage = FindPageFrm();
1396         if ( pPage )
1397         {
1398             if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
1399             {
1400                 //Das sollte er sein (kann allenfalls temporaer anders sein,
1401                 //                    sollte uns das beunruhigen?)
1402                 rInfo.SetInfo( pPage, this );
1403                 return sal_False;
1404             }
1405             if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
1406                  (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
1407             {
1408                 //Das koennte er sein.
1409                 rInfo.SetInfo( pPage, this );
1410             }
1411         }
1412     }
1413     return sal_True;
1414 }
1415 
1416 /*************************************************************************
1417  *                      SwTxtFrm::PrepWidows()
1418  *************************************************************************/
1419 
1420 void SwTxtFrm::PrepWidows( const MSHORT nNeed, sal_Bool bNotify )
1421 {
1422     ASSERT(GetFollow() && nNeed, "+SwTxtFrm::Prepare: lost all friends");
1423 
1424     SwParaPortion *pPara = GetPara();
1425     if ( !pPara )
1426         return;
1427     pPara->SetPrepWidows( sal_True );
1428 
1429     // These two lines of code have been deleted for #102340#.
1430     // Obviously the widow control does not work if we have a
1431     // pMaster->pFollow->pFollow situation:
1432 
1433     // returnen oder nicht ist hier die Frage.
1434     // Ohne IsLocked() ist 5156 gefaehrlich,
1435     // ohne IsFollow() werden die Orphans unterdrueckt: 6968.
1436     // Abfrage auf IsLocked erst hier, weil das Flag gesetzt werden soll.
1437 //  if( IsLocked() && IsFollow() )
1438 //      return;
1439 
1440     MSHORT nHave = nNeed;
1441 
1442     // Wir geben ein paar Zeilen ab und schrumpfen im CalcPreps()
1443     SWAP_IF_NOT_SWAPPED( this )
1444 
1445     SwTxtSizeInfo aInf( this );
1446     SwTxtMargin aLine( this, &aInf );
1447     aLine.Bottom();
1448     xub_StrLen nTmpLen = aLine.GetCurr()->GetLen();
1449     while( nHave && aLine.PrevLine() )
1450     {
1451         if( nTmpLen )
1452             --nHave;
1453         nTmpLen = aLine.GetCurr()->GetLen();
1454     }
1455     // In dieser Ecke tummelten sich einige Bugs: 7513, 7606.
1456     // Wenn feststeht, dass Zeilen abgegeben werden koennen,
1457     // muss der Master darueber hinaus die Widow-Regel ueberpruefen.
1458     if( !nHave )
1459     {
1460         sal_Bool bSplit;
1461         if( !IsFollow() )   //Nur ein Master entscheidet ueber Orphans
1462         {
1463             const WidowsAndOrphans aWidOrp( this );
1464             bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() &&
1465                        aLine.GetLineNr() >= aLine.GetDropLines() );
1466         }
1467         else
1468             bSplit = sal_True;
1469 
1470         if( bSplit )
1471         {
1472             GetFollow()->SetOfst( aLine.GetEnd() );
1473             aLine.TruncLines( sal_True );
1474             if( pPara->IsFollowField() )
1475                 GetFollow()->SetFieldFollow( sal_True );
1476         }
1477     }
1478     if ( bNotify )
1479     {
1480         _InvalidateSize();
1481         InvalidatePage();
1482     }
1483 
1484     UNDO_SWAP( this )
1485 }
1486 
1487 /*************************************************************************
1488  *                      SwTxtFrm::Prepare
1489  *************************************************************************/
1490 
1491 sal_Bool lcl_ErgoVadis( SwTxtFrm* pFrm, xub_StrLen &rPos, const PrepareHint ePrep )
1492 {
1493     const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1494     if( ePrep == PREP_ERGOSUM )
1495     {
1496         if( !rFtnInfo.aErgoSum.Len() )
1497             return sal_False;;
1498         rPos = pFrm->GetOfst();
1499     }
1500     else
1501     {
1502         if( !rFtnInfo.aQuoVadis.Len() )
1503             return sal_False;
1504         if( pFrm->HasFollow() )
1505             rPos = pFrm->GetFollow()->GetOfst();
1506         else
1507             rPos = pFrm->GetTxt().Len();
1508         if( rPos )
1509             --rPos; // unser letztes Zeichen
1510     }
1511     return sal_True;
1512 }
1513 
1514 void SwTxtFrm::Prepare( const PrepareHint ePrep, const void* pVoid,
1515                         sal_Bool bNotify )
1516 {
1517     SwFrmSwapper aSwapper( this, sal_False );
1518 
1519 #if OSL_DEBUG_LEVEL > 1
1520     const SwTwips nDbgY = Frm().Top();
1521     (void)nDbgY;
1522 #endif
1523 
1524     if ( IsEmpty() )
1525     {
1526         switch ( ePrep )
1527         {
1528             case PREP_BOSS_CHGD:
1529                 SetInvalidVert( sal_True );  // Test
1530             case PREP_WIDOWS_ORPHANS:
1531             case PREP_WIDOWS:
1532             case PREP_FTN_GONE :    return;
1533 
1534             case PREP_POS_CHGD :
1535             {
1536                 // Auch in (spaltigen) Bereichen ist ein InvalidateSize notwendig,
1537                 // damit formatiert wird und ggf. das bUndersized gesetzt wird.
1538                 if( IsInFly() || IsInSct() )
1539                 {
1540                     SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1541                         GetUpper()->Prt().Bottom();
1542                     if( nTmpBottom < Frm().Bottom() )
1543                         break;
1544                 }
1545                 // Gibt es ueberhaupt Flys auf der Seite ?
1546                 SwTxtFly aTxtFly( this );
1547                 if( aTxtFly.IsOn() )
1548                 {
1549                     // Ueberlappt irgendein Fly ?
1550                     aTxtFly.Relax();
1551                     if ( aTxtFly.IsOn() || IsUndersized() )
1552                         break;
1553                 }
1554                 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue())
1555                     break;
1556 
1557                 GETGRID( FindPageFrm() )
1558                 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1559                     break;
1560 
1561                 // --> OD 2004-07-16 #i28701# - consider anchored objects
1562                 if ( GetDrawObjs() )
1563                     break;
1564                 // <--
1565 
1566                 return;
1567             }
1568             default:
1569                 break;
1570         }
1571     }
1572 
1573     if( !HasPara() && PREP_MUST_FIT != ePrep )
1574     {
1575         SetInvalidVert( sal_True );  // Test
1576         ASSERT( !IsLocked(), "SwTxtFrm::Prepare: three of a perfect pair" );
1577         if ( bNotify )
1578             InvalidateSize();
1579         else
1580             _InvalidateSize();
1581         return;
1582     }
1583 
1584     //Objekt mit Locking aus dem Cache holen.
1585     SwTxtLineAccess aAccess( this );
1586     SwParaPortion *pPara = aAccess.GetPara();
1587 
1588     switch( ePrep )
1589     {
1590         case PREP_MOVEFTN :     Frm().Height(0);
1591                                 Prt().Height(0);
1592                                 _InvalidatePrt();
1593                                 _InvalidateSize();
1594                                 // KEIN break
1595         case PREP_ADJUST_FRM :  pPara->SetPrepAdjust( sal_True );
1596                                 if( IsFtnNumFrm() != pPara->IsFtnNum() ||
1597                                     IsUndersized() )
1598                                 {
1599                                     InvalidateRange( SwCharRange( 0, 1 ), 1);
1600                                     if( GetOfst() && !IsFollow() )
1601                                         _SetOfst( 0 );
1602                                 }
1603                                 break;
1604         case PREP_MUST_FIT :        pPara->SetPrepMustFit( sal_True );
1605             /* no break here */
1606         case PREP_WIDOWS_ORPHANS :  pPara->SetPrepAdjust( sal_True );
1607                                     break;
1608 
1609         case PREP_WIDOWS :
1610             // MustFit ist staerker als alles anderes
1611             if( pPara->IsPrepMustFit() )
1612                 return;
1613             // Siehe Kommentar in WidowsAndOrphans::FindOrphans und CalcPreps()
1614             PrepWidows( *(const MSHORT *)pVoid, bNotify );
1615             break;
1616 
1617         case PREP_FTN :
1618         {
1619             SwTxtFtn *pFtn = (SwTxtFtn *)pVoid;
1620             if( IsInFtn() )
1621             {
1622                 // Bin ich der erste TxtFrm einer Fussnote ?
1623                 if( !GetPrev() )
1624                     // Wir sind also ein TxtFrm der Fussnote, die
1625                     // die Fussnotenzahl zur Anzeige bringen muss.
1626                     // Oder den ErgoSum-Text...
1627                     InvalidateRange( SwCharRange( 0, 1 ), 1);
1628 
1629                 if( !GetNext() )
1630                 {
1631                     // Wir sind der letzte Ftn, jetzt muessten die
1632                     // QuoVadis-Texte geupdated werden.
1633                     const SwFtnInfo &rFtnInfo = GetNode()->GetDoc()->GetFtnInfo();
1634                     if( !pPara->UpdateQuoVadis( rFtnInfo.aQuoVadis ) )
1635                     {
1636                         xub_StrLen nPos = pPara->GetParLen();
1637                         if( nPos )
1638                             --nPos;
1639                         InvalidateRange( SwCharRange( nPos, 1 ), 1);
1640                     }
1641                 }
1642             }
1643             else
1644             {
1645                 // Wir sind also der TxtFrm _mit_ der Fussnote
1646                 const xub_StrLen nPos = *pFtn->GetStart();
1647                 InvalidateRange( SwCharRange( nPos, 1 ), 1);
1648             }
1649             break;
1650         }
1651         case PREP_BOSS_CHGD :
1652         {
1653     // Test
1654             {
1655                 SetInvalidVert( sal_False );
1656                 sal_Bool bOld = IsVertical();
1657                 SetInvalidVert( sal_True );
1658                 if( bOld != IsVertical() )
1659                     InvalidateRange( SwCharRange( GetOfst(), STRING_LEN ) );
1660             }
1661 
1662             if( HasFollow() )
1663             {
1664                 xub_StrLen nNxtOfst = GetFollow()->GetOfst();
1665                 if( nNxtOfst )
1666                     --nNxtOfst;
1667                 InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1);
1668             }
1669             if( IsInFtn() )
1670             {
1671                 xub_StrLen nPos;
1672                 if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) )
1673                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1674                 if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) )
1675                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1676             }
1677             // 4739: Wenn wir ein Seitennummernfeld besitzen, muessen wir
1678             // die Stellen invalidieren.
1679             SwpHints *pHints = GetTxtNode()->GetpSwpHints();
1680             if( pHints )
1681             {
1682                 const sal_uInt16 nSize = pHints->Count();
1683                 const xub_StrLen nEnd = GetFollow() ?
1684                                     GetFollow()->GetOfst() : STRING_LEN;
1685                 for ( sal_uInt16 i = 0; i < nSize; ++i )
1686                 {
1687                     const SwTxtAttr *pHt = (*pHints)[i];
1688                     const xub_StrLen nStart = *pHt->GetStart();
1689                     if( nStart >= GetOfst() )
1690                     {
1691                         if( nStart >= nEnd )
1692                             i = nSize;          // fuehrt das Ende herbei
1693                         else
1694                         {
1695                 // 4029: wenn wir zurueckfliessen und eine Ftn besitzen, so
1696                 // fliesst die Ftn in jedem Fall auch mit. Damit sie nicht im
1697                 // Weg steht, schicken wir uns ein ADJUST_FRM.
1698                 // pVoid != 0 bedeutet MoveBwd()
1699                             const MSHORT nWhich = pHt->Which();
1700                             if( RES_TXTATR_FIELD == nWhich ||
1701                                 (HasFtn() && pVoid && RES_TXTATR_FTN == nWhich))
1702                             InvalidateRange( SwCharRange( nStart, 1 ), 1 );
1703                         }
1704                     }
1705                 }
1706             }
1707             // A new boss, a new chance for growing
1708             if( IsUndersized() )
1709             {
1710                 _InvalidateSize();
1711                 InvalidateRange( SwCharRange( GetOfst(), 1 ), 1);
1712             }
1713             break;
1714         }
1715 
1716         case PREP_POS_CHGD :
1717         {
1718             if ( GetValidPrtAreaFlag() )
1719             {
1720                 GETGRID( FindPageFrm() )
1721                 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1722                     InvalidatePrt();
1723             }
1724 
1725             // Falls wir mit niemandem ueberlappen:
1726             // Ueberlappte irgendein Fly _vor_ der Positionsaenderung ?
1727             sal_Bool bFormat = pPara->HasFly();
1728             if( !bFormat )
1729             {
1730                 if( IsInFly() )
1731                 {
1732                     SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1733                         GetUpper()->Prt().Bottom();
1734                     if( nTmpBottom < Frm().Bottom() )
1735                         bFormat = sal_True;
1736                 }
1737                 if( !bFormat )
1738                 {
1739                     if ( GetDrawObjs() )
1740                     {
1741                         const sal_uInt32 nCnt = GetDrawObjs()->Count();
1742                         for ( MSHORT i = 0; i < nCnt; ++i )
1743                         {
1744                             SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
1745                             // --> OD 2004-07-16 #i28701# - consider all
1746                             // to-character anchored objects
1747                             if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
1748                                     == FLY_AT_CHAR )
1749                             {
1750                                 bFormat = sal_True;
1751                                 break;
1752                             }
1753                         }
1754                     }
1755                     if( !bFormat )
1756                     {
1757                         // Gibt es ueberhaupt Flys auf der Seite ?
1758                         SwTxtFly aTxtFly( this );
1759                         if( aTxtFly.IsOn() )
1760                         {
1761                             // Ueberlappt irgendein Fly ?
1762                             aTxtFly.Relax();
1763                             bFormat = aTxtFly.IsOn() || IsUndersized();
1764                         }
1765                     }
1766                 }
1767             }
1768 
1769             if( bFormat )
1770             {
1771                 if( !IsLocked() )
1772                 {
1773                     if( pPara->GetRepaint()->HasArea() )
1774                         SetCompletePaint();
1775                     Init();
1776                     pPara = 0;
1777                     _InvalidateSize();
1778                 }
1779             }
1780             else
1781             {
1782                 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1783                     Prepare( PREP_REGISTER, 0, bNotify );
1784                 // Durch Positionsverschiebungen mit Ftns muessen die
1785                 // Frames neu adjustiert werden.
1786                 else if( HasFtn() )
1787                 {
1788                     Prepare( PREP_ADJUST_FRM, 0, bNotify );
1789                     _InvalidateSize();
1790                 }
1791                 else
1792                     return;     // damit kein SetPrep() erfolgt.
1793             }
1794             break;
1795         }
1796         case PREP_REGISTER:
1797             if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1798             {
1799                 pPara->SetPrepAdjust( sal_True );
1800                 CalcLineSpace();
1801                 InvalidateSize();
1802                 _InvalidatePrt();
1803                 SwFrm* pNxt;
1804                 if ( 0 != ( pNxt = GetIndNext() ) )
1805                 {
1806                     pNxt->_InvalidatePrt();
1807                     if ( pNxt->IsLayoutFrm() )
1808                         pNxt->InvalidatePage();
1809                 }
1810                 SetCompletePaint();
1811             }
1812             break;
1813         case PREP_FTN_GONE :
1814             {
1815                 // Wenn ein Follow uns ruft, weil eine Fussnote geloescht wird, muss unsere
1816                 // letzte Zeile formatiert werden, damit ggf. die erste Zeile des Follows
1817                 // hochrutschen kann, die extra auf die naechste Seite gerutscht war, um mit
1818                 // der Fussnote zusammen zu sein, insbesondere bei spaltigen Bereichen.
1819                 ASSERT( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" );
1820                 xub_StrLen nPos = GetFollow()->GetOfst();
1821                 if( IsFollow() && GetOfst() == nPos )       // falls wir gar keine Textmasse besitzen,
1822                     FindMaster()->Prepare( PREP_FTN_GONE ); // rufen wir das Prepare unseres Masters
1823                 if( nPos )
1824                     --nPos; // das Zeichen vor unserem Follow
1825                 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1826                 return;
1827             }
1828         case PREP_ERGOSUM:
1829         case PREP_QUOVADIS:
1830             {
1831                 xub_StrLen nPos;
1832                 if( lcl_ErgoVadis( this, nPos, ePrep ) )
1833                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1834             }
1835             break;
1836         case PREP_FLY_ATTR_CHG:
1837         {
1838             if( pVoid )
1839             {
1840                 xub_StrLen nWhere = CalcFlyPos( (SwFrmFmt*)pVoid );
1841                 ASSERT( STRING_LEN != nWhere, "Prepare: Why me?" );
1842                 InvalidateRange( SwCharRange( nWhere, 1 ) );
1843                 return;
1844             }
1845             // else ... Laufe in den Default-Switch
1846         }
1847         case PREP_CLEAR:
1848         default:
1849         {
1850             if( IsLocked() )
1851             {
1852                 if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep )
1853                 {
1854                     xub_StrLen nLen = ( GetFollow() ? GetFollow()->GetOfst() :
1855                                       STRING_LEN ) - GetOfst();
1856                     InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 );
1857                 }
1858             }
1859             else
1860             {
1861                 if( pPara->GetRepaint()->HasArea() )
1862                     SetCompletePaint();
1863                 Init();
1864                 pPara = 0;
1865                 if( GetOfst() && !IsFollow() )
1866                     _SetOfst( 0 );
1867                 if ( bNotify )
1868                     InvalidateSize();
1869                 else
1870                     _InvalidateSize();
1871             }
1872             return;     // damit kein SetPrep() erfolgt.
1873         }
1874     }
1875     if( pPara )
1876         pPara->SetPrep( sal_True );
1877 }
1878 
1879 /* -----------------11.02.99 17:56-------------------
1880  * Kleine Hilfsklasse mit folgender Funktion:
1881  * Sie soll eine Probeformatierung vorbereiten.
1882  * Der Frame wird in Groesse und Position angepasst, sein SwParaPortion zur Seite
1883  * gestellt und eine neue erzeugt, dazu wird formatiert mit gesetztem bTestFormat.
1884  * Im Dtor wird der TxtFrm wieder in seinen alten Zustand zurueckversetzt.
1885  *
1886  * --------------------------------------------------*/
1887 
1888 class SwTestFormat
1889 {
1890     SwTxtFrm *pFrm;
1891     SwParaPortion *pOldPara;
1892     SwRect aOldFrm, aOldPrt;
1893 public:
1894     SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPrv, SwTwips nMaxHeight );
1895     ~SwTestFormat();
1896 };
1897 
1898 SwTestFormat::SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPre, SwTwips nMaxHeight )
1899     : pFrm( pTxtFrm )
1900 {
1901     aOldFrm = pFrm->Frm();
1902     aOldPrt = pFrm->Prt();
1903 
1904     SWRECTFN( pFrm )
1905     SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)();
1906 
1907     pFrm->Frm() = pFrm->GetUpper()->Prt();
1908     pFrm->Frm() += pFrm->GetUpper()->Frm().Pos();
1909 
1910     (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight );
1911     if( pFrm->GetPrev() )
1912         (pFrm->Frm().*fnRect->fnSetPosY)(
1913                 (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() -
1914                 ( bVert ? nMaxHeight + 1 : 0 ) );
1915 
1916     SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1917     const SwBorderAttrs &rAttrs = *aAccess.Get();
1918     (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) );
1919 
1920     if( pPre )
1921     {
1922         SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre );
1923         (pFrm->Prt().*fnRect->fnSetPosY)( nUpper );
1924     }
1925     (pFrm->Prt().*fnRect->fnSetHeight)(
1926         Max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() -
1927                   (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) );
1928     (pFrm->Prt().*fnRect->fnSetWidth)(
1929         (pFrm->Frm().*fnRect->fnGetWidth)() -
1930         // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
1931         ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) );
1932     pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL;
1933     pFrm->SetPara( new SwParaPortion(), sal_False );
1934 
1935     ASSERT( ! pFrm->IsSwapped(), "A frame is swapped before _Format" );
1936 
1937     if ( pFrm->IsVertical() )
1938         pFrm->SwapWidthAndHeight();
1939 
1940     SwTxtFormatInfo aInf( pFrm, sal_False, sal_True, sal_True );
1941     SwTxtFormatter  aLine( pFrm, &aInf );
1942 
1943     pFrm->_Format( aLine, aInf );
1944 
1945     if ( pFrm->IsVertical() )
1946         pFrm->SwapWidthAndHeight();
1947 
1948     ASSERT( ! pFrm->IsSwapped(), "A frame is swapped after _Format" );
1949 }
1950 
1951 SwTestFormat::~SwTestFormat()
1952 {
1953     pFrm->Frm() = aOldFrm;
1954     pFrm->Prt() = aOldPrt;
1955     pFrm->SetPara( pOldPara );
1956 }
1957 
1958 sal_Bool SwTxtFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, sal_Bool &bSplit )
1959 {
1960     PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 )
1961 
1962     if( IsLocked() && GetUpper()->Prt().Width() <= 0 )
1963         return sal_False;
1964 
1965     SwTestFormat aSave( this, pPrv, rMaxHeight );
1966 
1967     return SwTxtFrm::WouldFit( rMaxHeight, bSplit, sal_True );
1968 }
1969 
1970 
1971 /*************************************************************************
1972  *                      SwTxtFrm::WouldFit()
1973  *************************************************************************/
1974 
1975 /* SwTxtFrm::WouldFit()
1976  * sal_True: wenn ich aufspalten kann.
1977  * Es soll und braucht nicht neu formatiert werden.
1978  * Wir gehen davon aus, dass bereits formatiert wurde und dass
1979  * die Formatierungsdaten noch aktuell sind.
1980  * Wir gehen davon aus, dass die Framebreiten des evtl. Masters und
1981  * Follows gleich sind. Deswegen wird kein FindBreak() mit FindOrphans()
1982  * gerufen.
1983  * Die benoetigte Hoehe wird von nMaxHeight abgezogen!
1984  */
1985 
1986 sal_Bool SwTxtFrm::WouldFit( SwTwips &rMaxHeight, sal_Bool &bSplit, sal_Bool bTst )
1987 {
1988     ASSERT( ! IsVertical() || ! IsSwapped(),
1989             "SwTxtFrm::WouldFit with swapped frame" );
1990     SWRECTFN( this );
1991 
1992     if( IsLocked() )
1993         return sal_False;
1994 
1995     //Kann gut sein, dass mir der IdleCollector mir die gecachten
1996     //Informationen entzogen hat.
1997     if( !IsEmpty() )
1998         GetFormatted();
1999 
2000     // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph
2001     // can *not* be applied, if test format is in progress. The test format doesn't
2002     // adjust the frame and the printing area - see method <SwTxtFrm::_Format(..)>,
2003     // which is called in <SwTxtFrm::TestFormat(..)>
2004     if ( IsEmpty() && !bTst )
2005     {
2006         bSplit = sal_False;
2007         SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height();
2008         if( rMaxHeight < nHeight )
2009             return sal_False;
2010         else
2011         {
2012             rMaxHeight -= nHeight;
2013             return sal_True;
2014         }
2015     }
2016 
2017     // In sehr unguenstigen Faellen kann GetPara immer noch 0 sein.
2018     // Dann returnen wir sal_True, um auf der neuen Seite noch einmal
2019     // anformatiert zu werden.
2020     ASSERT( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" );
2021     if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) )
2022         return sal_True;
2023 
2024     // Da das Orphan-Flag nur sehr fluechtig existiert, wird als zweite
2025     // Bedingung  ueberprueft, ob die Rahmengroesse durch CalcPreps
2026     // auf riesengross gesetzt wird, um ein MoveFwd zu erzwingen.
2027     if( IsWidow() || ( bVert ?
2028                        ( 0 == Frm().Left() ) :
2029                        ( LONG_MAX - 20000 < Frm().Bottom() ) ) )
2030     {
2031         SetWidow(sal_False);
2032         if ( GetFollow() )
2033         {
2034             // Wenn wir hier durch eine Widow-Anforderung unseres Follows gelandet
2035             // sind, wird ueberprueft, ob es ueberhaupt einen Follow mit einer
2036             // echten Hoehe gibt, andernfalls (z.B. in neu angelegten SctFrms)
2037             // ignorieren wir das IsWidow() und pruefen doch noch, ob wir
2038             // genung Platz finden.
2039             if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) ||
2040                   (   bVert && 0 < Frm().Left() ) ) &&
2041                   ( GetFollow()->IsVertical() ?
2042                     !GetFollow()->Frm().Width() :
2043                     !GetFollow()->Frm().Height() ) )
2044             {
2045                 SwTxtFrm* pFoll = GetFollow()->GetFollow();
2046                 while( pFoll &&
2047                         ( pFoll->IsVertical() ?
2048                          !pFoll->Frm().Width() :
2049                          !pFoll->Frm().Height() ) )
2050                     pFoll = pFoll->GetFollow();
2051                 if( pFoll )
2052                     return sal_False;
2053             }
2054             else
2055                 return sal_False;
2056         }
2057     }
2058 
2059     SWAP_IF_NOT_SWAPPED( this );
2060 
2061     SwTxtSizeInfo aInf( this );
2062     SwTxtMargin aLine( this, &aInf );
2063 
2064     WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit );
2065 
2066     sal_Bool bRet = sal_True;
2067 
2068     aLine.Bottom();
2069     // Ist Aufspalten ueberhaupt notwendig?
2070     if ( 0 != ( bSplit = !aFrmBreak.IsInside( aLine ) ) )
2071         bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst );
2072     else
2073     {
2074         //Wir brauchen die Gesamthoehe inklusive der aktuellen Zeile
2075         aLine.Top();
2076         do
2077         {
2078             rMaxHeight -= aLine.GetLineHeight();
2079         } while ( aLine.Next() );
2080     }
2081 
2082     UNDO_SWAP( this )
2083 
2084     return bRet;
2085 }
2086 
2087 
2088 /*************************************************************************
2089  *                      SwTxtFrm::GetParHeight()
2090  *************************************************************************/
2091 
2092 KSHORT SwTxtFrm::GetParHeight() const
2093 {
2094     ASSERT( ! IsVertical() || ! IsSwapped(),
2095             "SwTxtFrm::GetParHeight with swapped frame" )
2096 
2097     if( !HasPara() )
2098     {   // Fuer nichtleere Absaetze ist dies ein Sonderfall, da koennen wir
2099         // bei UnderSized ruhig nur 1 Twip mehr anfordern.
2100         KSHORT nRet = (KSHORT)Prt().SSize().Height();
2101         if( IsUndersized() )
2102         {
2103             if( IsEmpty() )
2104                 nRet = (KSHORT)EmptyHeight();
2105             else
2106                 ++nRet;
2107         }
2108         return nRet;
2109     }
2110 
2111     // FME, OD 08.01.2004 #i11859# - refactoring and improve code
2112     const SwLineLayout* pLineLayout = GetPara();
2113     KSHORT nHeight = pLineLayout->GetRealHeight();
2114     if( GetOfst() && !IsFollow() )  // Ist dieser Absatz gescrollt? Dann ist unsere
2115         nHeight *= 2;               // bisherige Hoehe mind. eine Zeilenhoehe zu gering
2116     // OD 2004-03-04 #115793#
2117     while ( pLineLayout && pLineLayout->GetNext() )
2118     {
2119         pLineLayout = pLineLayout->GetNext();
2120         nHeight = nHeight + pLineLayout->GetRealHeight();
2121     }
2122 
2123     return nHeight;
2124 }
2125 
2126 
2127 /*************************************************************************
2128  *                      SwTxtFrm::GetFormatted()
2129  *************************************************************************/
2130 
2131 // returnt this _immer_ im formatierten Zustand!
2132 SwTxtFrm* SwTxtFrm::GetFormatted( bool bForceQuickFormat )
2133 {
2134     SWAP_IF_SWAPPED( this )
2135 
2136     //Kann gut sein, dass mir der IdleCollector mir die gecachten
2137     //Informationen entzogen hat. Calc() ruft unser Format.
2138                       //Nicht bei leeren Absaetzen!
2139     if( !HasPara() && !(IsValid() && IsEmpty()) )
2140     {
2141         // Calc() muss gerufen werden, weil unsere Frameposition
2142         // nicht stimmen muss.
2143         const sal_Bool bFormat = GetValidSizeFlag();
2144         Calc();
2145         // Es kann durchaus sein, dass Calc() das Format()
2146         // nicht anstiess (weil wir einst vom Idle-Zerstoerer
2147         // aufgefordert wurden unsere Formatinformationen wegzuschmeissen).
2148         // 6995: Optimierung mit FormatQuick()
2149         if( bFormat && !FormatQuick( bForceQuickFormat ) )
2150             Format();
2151     }
2152 
2153     UNDO_SWAP( this )
2154 
2155     return this;
2156 }
2157 
2158 /*************************************************************************
2159  *                      SwTxtFrm::CalcFitToContent()
2160  *************************************************************************/
2161 
2162 SwTwips SwTxtFrm::CalcFitToContent()
2163 {
2164     // --> FME 2004-07-16 #i31490#
2165     // If we are currently locked, we better return with a
2166     // fairly reasonable value:
2167     if ( IsLocked() )
2168         return Prt().Width();
2169     // <--
2170 
2171     SwParaPortion* pOldPara = GetPara();
2172     SwParaPortion *pDummy = new SwParaPortion();
2173     SetPara( pDummy, false );
2174     const SwPageFrm* pPage = FindPageFrm();
2175 
2176     const Point   aOldFrmPos   = Frm().Pos();
2177     const SwTwips nOldFrmWidth = Frm().Width();
2178     const SwTwips nOldPrtWidth = Prt().Width();
2179     const SwTwips nPageWidth = GetUpper()->IsVertical() ?
2180                                pPage->Prt().Height() :
2181                                pPage->Prt().Width();
2182 
2183     Frm().Width( nPageWidth );
2184     Prt().Width( nPageWidth );
2185 
2186     // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2187     if ( IsRightToLeft() )
2188         Frm().Pos().X() += nOldFrmWidth - nPageWidth;
2189 
2190     // --> FME 2004-07-16 #i31490#
2191     SwTxtFrmLocker aLock( this );
2192     // <--
2193 
2194     SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2195     aInf.SetIgnoreFly( sal_True );
2196     SwTxtFormatter  aLine( this, &aInf );
2197     SwHookOut aHook( aInf );
2198 
2199     // --> OD 2005-09-06 #i54031# - assure mininum of MINLAY twips.
2200     const SwTwips nMax = Max( (SwTwips)MINLAY,
2201                               aLine._CalcFitToContent() + 1 );
2202     // <--
2203 
2204     Frm().Width( nOldFrmWidth );
2205     Prt().Width( nOldPrtWidth );
2206 
2207     // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2208     if ( IsRightToLeft() )
2209         Frm().Pos() = aOldFrmPos;
2210 
2211 
2212     SetPara( pOldPara );
2213 
2214     return nMax;
2215 }
2216 
2217 /** simulate format for a list item paragraph, whose list level attributes
2218     are in LABEL_ALIGNMENT mode, in order to determine additional first
2219     line offset for the real text formatting due to the value of label
2220     adjustment attribute of the list level.
2221 
2222     OD 2008-01-31 #newlistlevelattrs#
2223 
2224     @author OD
2225 */
2226 void SwTxtFrm::CalcAdditionalFirstLineOffset()
2227 {
2228     if ( IsLocked() )
2229         return;
2230 
2231     // reset additional first line offset
2232     mnAdditionalFirstLineOffset = 0;
2233 
2234     const SwTxtNode* pTxtNode( GetTxtNode() );
2235     if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->IsCountedInList() &&
2236          pTxtNode->GetNumRule() )
2237     {
2238         const SwNumFmt& rNumFmt =
2239                 pTxtNode->GetNumRule()->Get( static_cast<sal_uInt16>(pTxtNode->GetActualListLevel()) );
2240         if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2241         {
2242             // keep current paragraph portion and apply dummy paragraph portion
2243             SwParaPortion* pOldPara = GetPara();
2244             SwParaPortion *pDummy = new SwParaPortion();
2245             SetPara( pDummy, false );
2246 
2247             // lock paragraph
2248             SwTxtFrmLocker aLock( this );
2249 
2250             // simulate text formatting
2251             SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2252             aInf.SetIgnoreFly( sal_True );
2253             SwTxtFormatter aLine( this, &aInf );
2254             SwHookOut aHook( aInf );
2255             aLine._CalcFitToContent();
2256 
2257             // determine additional first line offset
2258             const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion();
2259             if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFtnNumPortion() )
2260             {
2261                 SwTwips nNumberPortionWidth( pFirstPortion->Width() );
2262 
2263                 const SwLinePortion* pPortion = pFirstPortion->GetPortion();
2264                 while ( pPortion &&
2265                         pPortion->InNumberGrp() && !pPortion->IsFtnNumPortion())
2266                 {
2267                     nNumberPortionWidth += pPortion->Width();
2268                     pPortion = pPortion->GetPortion();
2269                 }
2270 
2271                 if ( ( IsRightToLeft() &&
2272                        rNumFmt.GetNumAdjust() == SVX_ADJUST_LEFT ) ||
2273                      ( !IsRightToLeft() &&
2274                        rNumFmt.GetNumAdjust() == SVX_ADJUST_RIGHT ) )
2275                 {
2276                     mnAdditionalFirstLineOffset = -nNumberPortionWidth;
2277                 }
2278                 else if ( rNumFmt.GetNumAdjust() == SVX_ADJUST_CENTER )
2279                 {
2280                     mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2);
2281                 }
2282             }
2283 
2284             // restore paragraph portion
2285             SetPara( pOldPara );
2286         }
2287     }
2288 }
2289 
2290 /** determine height of last line for the calculation of the proportional line
2291     spacing
2292 
2293     OD 08.01.2004 #i11859#
2294     OD 2004-03-17 #i11860# - method <GetHeightOfLastLineForPropLineSpacing()>
2295     replace by method <_CalcHeightOfLastLine()>. Height of last line will be
2296     stored in new member <mnHeightOfLastLine> and can be accessed via method
2297     <GetHeightOfLastLine()>
2298     OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont>
2299     in order to force the usage of the former algorithm to determine the
2300     height of the last line, which uses the font.
2301 
2302     @author OD
2303 */
2304 void SwTxtFrm::_CalcHeightOfLastLine( const bool _bUseFont )
2305 {
2306     // --> OD 2006-11-13 #i71281#
2307     // invalidate printing area, if height of last line changes
2308     const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine );
2309     // <--
2310     // determine output device
2311     ViewShell* pVsh = getRootFrm()->GetCurrShell();
2312     ASSERT( pVsh, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no ViewShell" );
2313     // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2314     // There could be no <ViewShell> instance in the case of loading a binary
2315     // StarOffice file format containing an embedded Writer document.
2316     if ( !pVsh )
2317     {
2318         return;
2319     }
2320     OutputDevice* pOut = pVsh->GetOut();
2321     const IDocumentSettingAccess* pIDSA = GetTxtNode()->getIDocumentSettingAccess();
2322     if ( !pVsh->GetViewOptions()->getBrowseMode() ||
2323           pVsh->GetViewOptions()->IsPrtFormat() )
2324     {
2325         pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
2326     }
2327     ASSERT( pOut, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no OutputDevice" );
2328     // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2329     if ( !pOut )
2330     {
2331         return;
2332     }
2333     // <--
2334 
2335     // determine height of last line
2336 
2337     if ( _bUseFont || pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING ) )
2338     {
2339         // former determination of last line height for proprotional line
2340         // spacing - take height of font set at the paragraph
2341         SwFont aFont( GetAttrSet(), pIDSA );
2342 
2343         // Wir muessen dafuer sorgen, dass am OutputDevice der Font
2344         // korrekt restauriert wird, sonst droht ein Last!=Owner.
2345         if ( pLastFont )
2346         {
2347             SwFntObj *pOldFont = pLastFont;
2348             pLastFont = NULL;
2349             aFont.SetFntChg( sal_True );
2350             aFont.ChgPhysFnt( pVsh, *pOut );
2351             mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2352             pLastFont->Unlock();
2353             pLastFont = pOldFont;
2354             pLastFont->SetDevFont( pVsh, *pOut );
2355         }
2356         else
2357         {
2358             Font aOldFont = pOut->GetFont();
2359             aFont.SetFntChg( sal_True );
2360             aFont.ChgPhysFnt( pVsh, *pOut );
2361             mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2362             pLastFont->Unlock();
2363             pLastFont = NULL;
2364             pOut->SetFont( aOldFont );
2365         }
2366     }
2367     else
2368     {
2369         // new determination of last line height - take actually height of last line
2370         // --> OD 2008-05-06 #i89000#
2371         // assure same results, if paragraph is undersized
2372         if ( IsUndersized() )
2373         {
2374             mnHeightOfLastLine = 0;
2375         }
2376         else
2377         {
2378             bool bCalcHeightOfLastLine = true;
2379             if ( !HasPara() )
2380             {
2381                 if ( IsEmpty() )
2382                 {
2383                     mnHeightOfLastLine = EmptyHeight();
2384                     bCalcHeightOfLastLine = false;
2385                 }
2386             }
2387 
2388             if ( bCalcHeightOfLastLine )
2389             {
2390                 ASSERT( HasPara(),
2391                         "<SwTxtFrm::_CalcHeightOfLastLine()> - missing paragraph portions." );
2392                 const SwLineLayout* pLineLayout = GetPara();
2393                 while ( pLineLayout && pLineLayout->GetNext() )
2394                 {
2395                     // iteration to last line
2396                     pLineLayout = pLineLayout->GetNext();
2397                 }
2398                 if ( pLineLayout )
2399                 {
2400                     SwTwips nAscent, nDescent, nDummy1, nDummy2;
2401                     // --> OD 2005-05-20 #i47162# - suppress consideration of
2402                     // fly content portions and the line portion.
2403                     pLineLayout->MaxAscentDescent( nAscent, nDescent,
2404                                                    nDummy1, nDummy2,
2405                                                    0, true );
2406                     // <--
2407                     // --> OD 2006-11-22 #i71281#
2408                     // Suppress wrong invalidation of printing area, if method is
2409                     // called recursive.
2410                     // Thus, member <mnHeightOfLastLine> is only set directly, if
2411                     // no recursive call is needed.
2412     //                mnHeightOfLastLine = nAscent + nDescent;
2413                     const SwTwips nNewHeightOfLastLine = nAscent + nDescent;
2414                     // --> OD 2005-05-20 #i47162# - if last line only contains
2415                     // fly content portions, <mnHeightOfLastLine> is zero.
2416                     // In this case determine height of last line by the font
2417                     if ( nNewHeightOfLastLine == 0 )
2418                     {
2419                         _CalcHeightOfLastLine( true );
2420                     }
2421                     else
2422                     {
2423                         mnHeightOfLastLine = nNewHeightOfLastLine;
2424                     }
2425                     // <--
2426                     // <--
2427                 }
2428             }
2429         }
2430         // <--
2431     }
2432     // --> OD 2006-11-13 #i71281#
2433     // invalidate printing area, if height of last line changes
2434     if ( mnHeightOfLastLine != mnOldHeightOfLastLine )
2435     {
2436         InvalidatePrt();
2437     }
2438     // <--
2439 }
2440 
2441 /*************************************************************************
2442  *                      SwTxtFrm::GetLineSpace()
2443  *************************************************************************/
2444 // OD 07.01.2004 #i11859# - change return data type
2445 //      add default parameter <_bNoPropLineSpacing> to control, if the
2446 //      value of a proportional line spacing is returned or not
2447 // OD 07.01.2004 - trying to describe purpose of method:
2448 //      Method returns the value of the inter line spacing for a text frame.
2449 //      Such a value exists for proportional line spacings ("1,5 Lines",
2450 //      "Double", "Proportional" and for leading line spacing ("Leading").
2451 //      By parameter <_bNoPropLineSpace> (default value false) it can be
2452 //      controlled, if the value of a proportional line spacing is returned.
2453 long SwTxtFrm::GetLineSpace( const bool _bNoPropLineSpace ) const
2454 {
2455     long nRet = 0;
2456 
2457     const SwAttrSet* pSet = GetAttrSet();
2458     const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
2459 
2460     switch( rSpace.GetInterLineSpaceRule() )
2461     {
2462         case SVX_INTER_LINE_SPACE_PROP:
2463         {
2464             // OD 07.01.2004 #i11859#
2465             if ( _bNoPropLineSpace )
2466             {
2467                 break;
2468             }
2469 
2470             // OD 2004-03-17 #i11860# - use method <GetHeightOfLastLine()>
2471             nRet = GetHeightOfLastLine();
2472 
2473             long nTmp = nRet;
2474             nTmp *= rSpace.GetPropLineSpace();
2475             nTmp /= 100;
2476             nTmp -= nRet;
2477             if ( nTmp > 0 )
2478                 nRet = nTmp;
2479             else
2480                 nRet = 0;
2481         }
2482             break;
2483         case SVX_INTER_LINE_SPACE_FIX:
2484         {
2485             if ( rSpace.GetInterLineSpace() > 0 )
2486                 nRet = rSpace.GetInterLineSpace();
2487         }
2488             break;
2489         default:
2490             break;
2491     }
2492     return nRet;
2493 }
2494 
2495 /*************************************************************************
2496  *                      SwTxtFrm::FirstLineHeight()
2497  *************************************************************************/
2498 
2499 KSHORT SwTxtFrm::FirstLineHeight() const
2500 {
2501     if ( !HasPara() )
2502     {
2503         if( IsEmpty() && IsValid() )
2504             return IsVertical() ? (KSHORT)Prt().Width() : (KSHORT)Prt().Height();
2505         return KSHRT_MAX;
2506     }
2507     const SwParaPortion *pPara = GetPara();
2508     if ( !pPara )
2509         return KSHRT_MAX;
2510 
2511     return pPara->Height();
2512 }
2513 
2514 MSHORT SwTxtFrm::GetLineCount( xub_StrLen nPos )
2515 {
2516     MSHORT nRet = 0;
2517     SwTxtFrm *pFrm = this;
2518     do
2519     {
2520         pFrm->GetFormatted();
2521         if( !pFrm->HasPara() )
2522             break;
2523         SwTxtSizeInfo aInf( pFrm );
2524         SwTxtMargin aLine( pFrm, &aInf );
2525         if( STRING_LEN == nPos )
2526             aLine.Bottom();
2527         else
2528             aLine.CharToLine( nPos );
2529         nRet = nRet + aLine.GetLineNr();
2530         pFrm = pFrm->GetFollow();
2531     } while ( pFrm && pFrm->GetOfst() <= nPos );
2532     return nRet;
2533 }
2534 
2535 void SwTxtFrm::ChgThisLines()
2536 {
2537     //not necassary to format here (GerFormatted etc.), because we have to come from there!
2538 
2539     sal_uLong nNew = 0;
2540     const SwLineNumberInfo &rInf = GetNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo();
2541     if ( GetTxt().Len() && HasPara() )
2542     {
2543         SwTxtSizeInfo aInf( this );
2544         SwTxtMargin aLine( this, &aInf );
2545         if ( rInf.IsCountBlankLines() )
2546         {
2547             aLine.Bottom();
2548             nNew = (sal_uLong)aLine.GetLineNr();
2549         }
2550         else
2551         {
2552             do
2553             {
2554                 if( aLine.GetCurr()->HasCntnt() )
2555                     ++nNew;
2556             } while ( aLine.NextLine() );
2557         }
2558     }
2559     else if ( rInf.IsCountBlankLines() )
2560         nNew = 1;
2561 
2562     if ( nNew != nThisLines )
2563     {
2564         if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
2565         {
2566             nAllLines -= nThisLines;
2567             nThisLines = nNew;
2568             nAllLines  += nThisLines;
2569             SwFrm *pNxt = GetNextCntntFrm();
2570             while( pNxt && pNxt->IsInTab() )
2571             {
2572                 if( 0 != (pNxt = pNxt->FindTabFrm()) )
2573                     pNxt = pNxt->FindNextCnt();
2574             }
2575             if( pNxt )
2576                 pNxt->InvalidateLineNum();
2577 
2578             //Extend repaint to the bottom.
2579             if ( HasPara() )
2580             {
2581                 SwRepaint *pRepaint = GetPara()->GetRepaint();
2582                 pRepaint->Bottom( Max( pRepaint->Bottom(),
2583                                        Frm().Top()+Prt().Bottom()));
2584             }
2585         }
2586         else //Paragraphs which are not counted should not manipulate the AllLines.
2587             nThisLines = nNew;
2588     }
2589 
2590     //mba: invalidating is not necessary; if mongolian script has a problem, it should be fixed at the ritgh place
2591     //with invalidating we probably get too much flickering
2592     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
2593     //Ugly. How can we hack if better?
2594     //InvalidatePage();
2595 }
2596 
2597 
2598 void SwTxtFrm::RecalcAllLines()
2599 {
2600     ValidateLineNum();
2601 
2602     const SwAttrSet *pAttrSet = GetAttrSet();
2603 
2604     if ( !IsInTab() )
2605     {
2606         const sal_uLong nOld = GetAllLines();
2607         const SwFmtLineNumber &rLineNum = pAttrSet->GetLineNumber();
2608         sal_uLong nNewNum;
2609         const bool bRestart = GetTxtNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo().IsRestartEachPage();
2610 
2611         if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() )
2612             nNewNum = rLineNum.GetStartValue() - 1;
2613         //If it is a follow or not has not be considered if it is a restart at each page; the
2614         //restart should also take affekt at follows.
2615         else if ( bRestart && FindPageFrm()->FindFirstBodyCntnt() == this )
2616         {
2617             nNewNum = 0;
2618         }
2619         else
2620         {
2621             SwCntntFrm *pPrv = GetPrevCntntFrm();
2622             while ( pPrv &&
2623                     (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) )
2624                 pPrv = pPrv->GetPrevCntntFrm();
2625 
2626             // --> FME 2007-06-22 #i78254# Restart line numbering at page change:
2627             // First body content may be in table!
2628             if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() )
2629                 pPrv = 0;
2630             // <--
2631 
2632             nNewNum = pPrv ? ((SwTxtFrm*)pPrv)->GetAllLines() : 0;
2633         }
2634         if ( rLineNum.IsCount() )
2635             nNewNum += GetThisLines();
2636 
2637         if ( nOld != nNewNum )
2638         {
2639             nAllLines = nNewNum;
2640             SwCntntFrm *pNxt = GetNextCntntFrm();
2641             while ( pNxt &&
2642                     (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) )
2643                 pNxt = pNxt->GetNextCntntFrm();
2644             if ( pNxt )
2645             {
2646                 if ( pNxt->GetUpper() != GetUpper() )
2647                     pNxt->InvalidateLineNum();
2648                 else
2649                     pNxt->_InvalidateLineNum();
2650             }
2651         }
2652     }
2653 }
2654 
2655 void SwTxtFrm::VisitPortions( SwPortionHandler& rPH ) const
2656 {
2657     const SwParaPortion* pPara = GetPara();
2658 
2659     if( pPara )
2660     {
2661         if ( IsFollow() )
2662             rPH.Skip( GetOfst() );
2663 
2664         const SwLineLayout* pLine = pPara;
2665         while ( pLine )
2666         {
2667             const SwLinePortion* pPor = pLine->GetFirstPortion();
2668             while ( pPor )
2669             {
2670                 pPor->HandlePortion( rPH );
2671                 pPor = pPor->GetPortion();
2672             }
2673 
2674             rPH.LineBreak();
2675             pLine = pLine->GetNext();
2676         }
2677     }
2678 
2679     rPH.Finish();
2680 }
2681 
2682 
2683 /*************************************************************************
2684  *                      SwTxtFrm::GetScriptInfo()
2685  *************************************************************************/
2686 
2687 const SwScriptInfo* SwTxtFrm::GetScriptInfo() const
2688 {
2689     const SwParaPortion* pPara = GetPara();
2690     return pPara ? &pPara->GetScriptInfo() : 0;
2691 }
2692 
2693 /*************************************************************************
2694  *                      lcl_CalcFlyBasePos()
2695  * Helper function for SwTxtFrm::CalcBasePosForFly()
2696  *************************************************************************/
2697 
2698 SwTwips lcl_CalcFlyBasePos( const SwTxtFrm& rFrm, SwRect aFlyRect,
2699                             SwTxtFly& rTxtFly )
2700 {
2701     SWRECTFN( (&rFrm) )
2702     SwTwips nRet = rFrm.IsRightToLeft() ?
2703                    (rFrm.Frm().*fnRect->fnGetRight)() :
2704                    (rFrm.Frm().*fnRect->fnGetLeft)();
2705 
2706     do
2707     {
2708         SwRect aRect = rTxtFly.GetFrm( aFlyRect );
2709         if ( 0 != (aRect.*fnRect->fnGetWidth)() )
2710         {
2711             if ( rFrm.IsRightToLeft() )
2712             {
2713                 if ( (aRect.*fnRect->fnGetRight)() -
2714                      (aFlyRect.*fnRect->fnGetRight)() >= 0 )
2715                 {
2716                     (aFlyRect.*fnRect->fnSetRight)(
2717                         (aRect.*fnRect->fnGetLeft)() );
2718                     nRet = (aRect.*fnRect->fnGetLeft)();
2719                 }
2720                 else
2721                     break;
2722             }
2723             else
2724             {
2725                 if ( (aFlyRect.*fnRect->fnGetLeft)() -
2726                      (aRect.*fnRect->fnGetLeft)() >= 0 )
2727                 {
2728                     (aFlyRect.*fnRect->fnSetLeft)(
2729                         (aRect.*fnRect->fnGetRight)() + 1 );
2730                     nRet = (aRect.*fnRect->fnGetRight)();
2731                 }
2732                 else
2733                     break;
2734             }
2735         }
2736         else
2737             break;
2738     }
2739     while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 );
2740 
2741     return nRet;
2742 }
2743 
2744 /*************************************************************************
2745  *                      SwTxtFrm::CalcBasePosForFly()
2746  *************************************************************************/
2747 
2748 void SwTxtFrm::CalcBaseOfstForFly()
2749 {
2750     ASSERT( !IsVertical() || !IsSwapped(),
2751             "SwTxtFrm::CalcBasePosForFly with swapped frame!" )
2752 
2753     const SwNode* pNode = GetTxtNode();
2754     if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_FLY_OFFSETS) )
2755         return;
2756 
2757     SWRECTFN( this )
2758 
2759     SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() );
2760 
2761     // Get first 'real' line and adjust position and height of line rectangle
2762     // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour,
2763     // if no 'real' line exists (empty paragraph with and without a dummy portion)
2764     {
2765         SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)();
2766         const SwLineLayout* pLay = GetPara();
2767         SwTwips nLineHeight = 200;
2768         while( pLay && pLay->IsDummy() && pLay->GetNext() )
2769         {
2770             nTop += pLay->Height();
2771             pLay = pLay->GetNext();
2772         }
2773         if ( pLay )
2774         {
2775             nLineHeight = pLay->Height();
2776         }
2777         (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight );
2778     }
2779 
2780     SwTxtFly aTxtFly( this );
2781     aTxtFly.SetIgnoreCurrentFrame( sal_True );
2782     aTxtFly.SetIgnoreContour( sal_True );
2783     // --> OD 2004-12-17 #118809# - ignore objects in page header|footer for
2784     // text frames not in page header|footer
2785     aTxtFly.SetIgnoreObjsInHeaderFooter( sal_True );
2786     // <--
2787     SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2788     aTxtFly.SetIgnoreCurrentFrame( sal_False );
2789     SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2790 
2791     // make values relative to frame start position
2792     SwTwips nLeft = IsRightToLeft() ?
2793                     (Frm().*fnRect->fnGetRight)() :
2794                     (Frm().*fnRect->fnGetLeft)();
2795 
2796     mnFlyAnchorOfst = nRet1 - nLeft;
2797     mnFlyAnchorOfstNoWrap = nRet2 - nLeft;
2798 }
2799 
2800 /* repaint all text frames of the given text node */
2801 void SwTxtFrm::repaintTextFrames( const SwTxtNode& rNode )
2802 {
2803     SwIterator<SwTxtFrm,SwTxtNode> aIter( rNode );
2804     for( const SwTxtFrm *pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
2805     {
2806         SwRect aRec( pFrm->PaintArea() );
2807         const SwRootFrm *pRootFrm = pFrm->getRootFrm();
2808         ViewShell *pCurShell = pRootFrm ? pRootFrm->GetCurrShell() : NULL;
2809         if( pCurShell )
2810             pCurShell->InvalidateWindows( aRec );
2811     }
2812 }
2813 
2814