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