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