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