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