Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <hintids.hxx>
21 : #include <hints.hxx>
22 : #include <svl/ctloptions.hxx>
23 : #include <sfx2/printer.hxx>
24 : #include <sfx2/sfxuno.hxx>
25 : #include <editeng/langitem.hxx>
26 : #include <editeng/lspcitem.hxx>
27 : #include <editeng/lrspitem.hxx>
28 : #include <editeng/ulspitem.hxx>
29 : #include <editeng/brushitem.hxx>
30 : #include <editeng/pgrditem.hxx>
31 : #include <swmodule.hxx>
32 : #include <SwSmartTagMgr.hxx>
33 : #include <doc.hxx>
34 : #include <IDocumentSettingAccess.hxx>
35 : #include <IDocumentDeviceAccess.hxx>
36 : #include <IDocumentFieldsAccess.hxx>
37 : #include "rootfrm.hxx"
38 : #include <pagefrm.hxx>
39 : #include <viewsh.hxx>
40 : #include <pam.hxx>
41 : #include <ndtxt.hxx>
42 : #include <txtatr.hxx>
43 : #include <paratr.hxx>
44 : #include <viewopt.hxx>
45 : #include <dflyobj.hxx>
46 : #include <flyfrm.hxx>
47 : #include <tabfrm.hxx>
48 : #include <frmtool.hxx>
49 : #include <pagedesc.hxx>
50 : #include <tgrditem.hxx>
51 : #include <dbg_lay.hxx>
52 : #include <fmtfld.hxx>
53 : #include <fmtftn.hxx>
54 : #include <txtfld.hxx>
55 : #include <txtftn.hxx>
56 : #include <charatr.hxx>
57 : #include <ftninfo.hxx>
58 : #include <fmtline.hxx>
59 : #include <txtfrm.hxx>
60 : #include <sectfrm.hxx>
61 : #include <itrform2.hxx>
62 : #include <widorp.hxx>
63 : #include <txtcache.hxx>
64 : #include <fntcache.hxx>
65 : #include <SwGrammarMarkUp.hxx>
66 : #include <lineinfo.hxx>
67 : #include <SwPortionHandler.hxx>
68 : #include <dcontact.hxx>
69 : #include <sortedobjs.hxx>
70 : #include <txtflcnt.hxx>
71 : #include <fmtflcnt.hxx>
72 : #include <fmtcntnt.hxx>
73 : #include <numrule.hxx>
74 : #include <swtable.hxx>
75 : #include <fldupde.hxx>
76 : #include <IGrammarContact.hxx>
77 : #include <calbck.hxx>
78 : #include <ftnidx.hxx>
79 :
80 2271551 : TYPEINIT1( SwTextFrm, SwContentFrm );
81 :
82 : /// Switches width and height of the text frame
83 92 : void SwTextFrm::SwapWidthAndHeight()
84 : {
85 92 : if ( ! bIsSwapped )
86 : {
87 46 : const long nPrtOfstX = Prt().Pos().X();
88 46 : Prt().Pos().X() = Prt().Pos().Y();
89 46 : if( IsVertLR() )
90 0 : Prt().Pos().Y() = nPrtOfstX;
91 : else
92 46 : Prt().Pos().Y() = Frm().Width() - ( nPrtOfstX + Prt().Width() );
93 :
94 : }
95 : else
96 : {
97 46 : const long nPrtOfstY = Prt().Pos().Y();
98 46 : Prt().Pos().Y() = Prt().Pos().X();
99 46 : if( IsVertLR() )
100 0 : Prt().Pos().X() = nPrtOfstY;
101 : else
102 46 : Prt().Pos().X() = Frm().Height() - ( nPrtOfstY + Prt().Height() );
103 : }
104 :
105 92 : const long nFrmWidth = Frm().Width();
106 92 : Frm().Width( Frm().Height() );
107 92 : Frm().Height( nFrmWidth );
108 92 : const long nPrtWidth = Prt().Width();
109 92 : Prt().Width( Prt().Height() );
110 92 : Prt().Height( nPrtWidth );
111 :
112 92 : bIsSwapped = ! bIsSwapped;
113 92 : }
114 :
115 : /**
116 : * Calculates the coordinates of a rectangle when switching from
117 : * horizontal to vertical layout.
118 : */
119 0 : void SwTextFrm::SwitchHorizontalToVertical( SwRect& rRect ) const
120 : {
121 : // calc offset inside frame
122 : long nOfstX, nOfstY;
123 0 : if ( IsVertLR() )
124 : {
125 0 : nOfstX = rRect.Left() - Frm().Left();
126 0 : nOfstY = rRect.Top() - Frm().Top();
127 : }
128 : else
129 : {
130 0 : nOfstX = rRect.Left() - Frm().Left();
131 0 : nOfstY = rRect.Top() + rRect.Height() - Frm().Top();
132 : }
133 :
134 0 : const long nWidth = rRect.Width();
135 0 : const long nHeight = rRect.Height();
136 :
137 0 : if ( IsVertLR() )
138 0 : rRect.Left(Frm().Left() + nOfstY);
139 : else
140 : {
141 0 : if ( bIsSwapped )
142 0 : rRect.Left( Frm().Left() + Frm().Height() - nOfstY );
143 : else
144 : // frame is rotated
145 0 : rRect.Left( Frm().Left() + Frm().Width() - nOfstY );
146 : }
147 :
148 0 : rRect.Top( Frm().Top() + nOfstX );
149 0 : rRect.Width( nHeight );
150 0 : rRect.Height( nWidth );
151 0 : }
152 :
153 : /**
154 : * Calculates the coordinates of a point when switching from
155 : * horizontal to vertical layout.
156 : */
157 27 : void SwTextFrm::SwitchHorizontalToVertical( Point& rPoint ) const
158 : {
159 : // calc offset inside frame
160 27 : const long nOfstX = rPoint.X() - Frm().Left();
161 27 : const long nOfstY = rPoint.Y() - Frm().Top();
162 27 : if ( IsVertLR() )
163 0 : rPoint.X() = Frm().Left() + nOfstY;
164 : else
165 : {
166 27 : if ( bIsSwapped )
167 27 : rPoint.X() = Frm().Left() + Frm().Height() - nOfstY;
168 : else
169 : // calc rotated coords
170 0 : rPoint.X() = Frm().Left() + Frm().Width() - nOfstY;
171 : }
172 :
173 27 : rPoint.Y() = Frm().Top() + nOfstX;
174 27 : }
175 :
176 : /**
177 : * Calculates the a limit value when switching from
178 : * horizontal to vertical layout.
179 : */
180 0 : long SwTextFrm::SwitchHorizontalToVertical( long nLimit ) const
181 : {
182 0 : Point aTmp( 0, nLimit );
183 0 : SwitchHorizontalToVertical( aTmp );
184 0 : return aTmp.X();
185 : }
186 :
187 : /**
188 : * Calculates the coordinates of a rectangle when switching from
189 : * vertical to horizontal layout.
190 : */
191 0 : void SwTextFrm::SwitchVerticalToHorizontal( SwRect& rRect ) const
192 : {
193 : long nOfstX;
194 :
195 : // calc offset inside frame
196 0 : if ( IsVertLR() )
197 0 : nOfstX = rRect.Left() - Frm().Left();
198 : else
199 : {
200 0 : if ( bIsSwapped )
201 0 : nOfstX = Frm().Left() + Frm().Height() - ( rRect.Left() + rRect.Width() );
202 : else
203 0 : nOfstX = Frm().Left() + Frm().Width() - ( rRect.Left() + rRect.Width() );
204 : }
205 :
206 0 : const long nOfstY = rRect.Top() - Frm().Top();
207 0 : const long nWidth = rRect.Height();
208 0 : const long nHeight = rRect.Width();
209 :
210 : // calc rotated coords
211 0 : rRect.Left( Frm().Left() + nOfstY );
212 0 : rRect.Top( Frm().Top() + nOfstX );
213 0 : rRect.Width( nWidth );
214 0 : rRect.Height( nHeight );
215 0 : }
216 :
217 : /**
218 : * Calculates the coordinates of a point when switching from
219 : * vertical to horizontal layout.
220 : */
221 0 : void SwTextFrm::SwitchVerticalToHorizontal( Point& rPoint ) const
222 : {
223 : long nOfstX;
224 :
225 : // calc offset inside frame
226 0 : if ( IsVertLR() )
227 0 : nOfstX = rPoint.X() - Frm().Left();
228 : else
229 : {
230 0 : if ( bIsSwapped )
231 0 : nOfstX = Frm().Left() + Frm().Height() - rPoint.X();
232 : else
233 0 : nOfstX = Frm().Left() + Frm().Width() - rPoint.X();
234 : }
235 :
236 0 : const long nOfstY = rPoint.Y() - Frm().Top();
237 :
238 : // calc rotated coords
239 0 : rPoint.X() = Frm().Left() + nOfstY;
240 0 : rPoint.Y() = Frm().Top() + nOfstX;
241 0 : }
242 :
243 : /**
244 : * Calculates the a limit value when switching from
245 : * vertical to horizontal layout.
246 : */
247 0 : long SwTextFrm::SwitchVerticalToHorizontal( long nLimit ) const
248 : {
249 0 : Point aTmp( nLimit, 0 );
250 0 : SwitchVerticalToHorizontal( aTmp );
251 0 : return aTmp.Y();
252 : }
253 :
254 848071 : SwFrmSwapper::SwFrmSwapper( const SwTextFrm* pTextFrm, bool bSwapIfNotSwapped )
255 848071 : : pFrm( pTextFrm ), bUndo( false )
256 : {
257 848086 : if ( pFrm->IsVertical() &&
258 34 : ( ( bSwapIfNotSwapped && ! pFrm->IsSwapped() ) ||
259 38 : ( ! bSwapIfNotSwapped && pFrm->IsSwapped() ) ) )
260 : {
261 15 : bUndo = true;
262 15 : const_cast<SwTextFrm*>(pFrm)->SwapWidthAndHeight();
263 : }
264 848071 : }
265 :
266 848071 : SwFrmSwapper::~SwFrmSwapper()
267 : {
268 848071 : if ( bUndo )
269 15 : const_cast<SwTextFrm*>(pFrm)->SwapWidthAndHeight();
270 848071 : }
271 :
272 352 : void SwTextFrm::SwitchLTRtoRTL( SwRect& rRect ) const
273 : {
274 352 : SWAP_IF_NOT_SWAPPED swap(const_cast<SwTextFrm *>(this));
275 :
276 352 : long nWidth = rRect.Width();
277 704 : rRect.Left( 2 * ( Frm().Left() + Prt().Left() ) +
278 704 : Prt().Width() - rRect.Right() - 1 );
279 :
280 352 : rRect.Width( nWidth );
281 352 : }
282 :
283 78 : void SwTextFrm::SwitchLTRtoRTL( Point& rPoint ) const
284 : {
285 78 : SWAP_IF_NOT_SWAPPED swap(const_cast<SwTextFrm *>(this));
286 :
287 78 : rPoint.X() = 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rPoint.X() - 1;
288 78 : }
289 :
290 24914 : SwLayoutModeModifier::SwLayoutModeModifier( const OutputDevice& rOutp ) :
291 24914 : rOut( rOutp ), nOldLayoutMode( rOutp.GetLayoutMode() )
292 : {
293 24914 : }
294 :
295 24914 : SwLayoutModeModifier::~SwLayoutModeModifier()
296 : {
297 24914 : const_cast<OutputDevice&>(rOut).SetLayoutMode( nOldLayoutMode );
298 24914 : }
299 :
300 2629 : void SwLayoutModeModifier::Modify( bool bChgToRTL )
301 : {
302 : const_cast<OutputDevice&>(rOut).SetLayoutMode( bChgToRTL ?
303 : TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL :
304 2629 : TEXT_LAYOUT_BIDI_STRONG );
305 2629 : }
306 :
307 22804 : void SwLayoutModeModifier::SetAuto()
308 : {
309 22804 : const ComplexTextLayoutMode nNewLayoutMode = nOldLayoutMode & ~TEXT_LAYOUT_BIDI_STRONG;
310 22804 : const_cast<OutputDevice&>(rOut).SetLayoutMode( nNewLayoutMode );
311 22804 : }
312 :
313 180058 : SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) :
314 180058 : rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() )
315 : {
316 180058 : LanguageType eLang = eCurLang;
317 180058 : const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals();
318 :
319 180058 : if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals )
320 0 : eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
321 180058 : else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals )
322 180058 : eLang = LANGUAGE_ENGLISH;
323 0 : else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals )
324 0 : eLang = ::GetAppLanguage();
325 :
326 180058 : const_cast<OutputDevice&>(rOut).SetDigitLanguage( eLang );
327 180058 : }
328 :
329 180058 : SwDigitModeModifier::~SwDigitModeModifier()
330 : {
331 180058 : const_cast<OutputDevice&>(rOut).SetDigitLanguage( nOldLanguageType );
332 180058 : }
333 :
334 15371 : void SwTextFrm::Init()
335 : {
336 : OSL_ENSURE( !IsLocked(), "+SwTextFrm::Init: this is locked." );
337 15371 : if( !IsLocked() )
338 : {
339 15371 : ClearPara();
340 15371 : ResetBlinkPor();
341 : // set flags directly to save a ResetPreps call,
342 : // and thereby an unnecessary GetPara call
343 : // don't set bOrphan, bLocked or bWait to false!
344 : // bOrphan = bFlag7 = bFlag8 = false;
345 : }
346 15371 : }
347 :
348 36977 : SwTextFrm::SwTextFrm(SwTextNode * const pNode, SwFrm* pSib )
349 : : SwContentFrm( pNode, pSib )
350 : , nAllLines( 0 )
351 : , nThisLines( 0 )
352 : , mnFlyAnchorOfst( 0 )
353 : , mnFlyAnchorOfstNoWrap( 0 )
354 : , mnFootnoteLine( 0 )
355 : , mnHeightOfLastLine( 0 ) // OD 2004-03-17 #i11860#
356 : , mnAdditionalFirstLineOffset( 0 )
357 : , nOfst( 0 )
358 : , nCacheIdx( USHRT_MAX )
359 : , bLocked( false )
360 : , bWidow( false )
361 : , bJustWidow( false )
362 : , bEmpty( false )
363 : , bInFootnoteConnect( false )
364 : , bFootnote( false )
365 : , bRepaint( false )
366 : , bBlinkPor( false )
367 : , bFieldFollow( false )
368 : , bHasAnimation( false )
369 : , bIsSwapped( false )
370 36977 : , mbFollowFormatAllowed( true ) // OD 14.03.2003 #i11760#
371 : {
372 36977 : mnFrmType = FRM_TXT;
373 36977 : }
374 :
375 36151 : void SwTextFrm::DestroyImpl()
376 : {
377 : // Remove associated SwParaPortion from pTextCache
378 36151 : ClearPara();
379 :
380 : const SwContentNode* pCNd;
381 144604 : if( 0 != ( pCNd = PTR_CAST( SwContentNode, GetRegisteredIn() )) &&
382 144604 : !pCNd->GetDoc()->IsInDtor() && HasFootnote() )
383 : {
384 67 : SwTextNode *pTextNd = static_cast<SwTextFrm*>(this)->GetTextNode();
385 67 : const SwFootnoteIdxs &rFootnoteIdxs = pCNd->GetDoc()->GetFootnoteIdxs();
386 67 : size_t nPos = 0;
387 67 : sal_uLong nIndex = pCNd->GetIndex();
388 67 : rFootnoteIdxs.SeekEntry( *pTextNd, &nPos );
389 67 : if( nPos < rFootnoteIdxs.size() )
390 : {
391 148 : while( nPos && pTextNd == &(rFootnoteIdxs[ nPos ]->GetTextNode()) )
392 14 : --nPos;
393 67 : if( nPos || pTextNd != &(rFootnoteIdxs[ nPos ]->GetTextNode()) )
394 13 : ++nPos;
395 : }
396 209 : while( nPos < rFootnoteIdxs.size() )
397 : {
398 88 : SwTextFootnote* pTextFootnote = rFootnoteIdxs[ nPos ];
399 88 : if( pTextFootnote->GetTextNode().GetIndex() > nIndex )
400 13 : break;
401 75 : pTextFootnote->DelFrms( this );
402 75 : ++nPos;
403 : }
404 : }
405 :
406 36151 : SwContentFrm::DestroyImpl();
407 36151 : }
408 :
409 72302 : SwTextFrm::~SwTextFrm()
410 : {
411 72302 : }
412 :
413 198023 : const OUString& SwTextFrm::GetText() const
414 : {
415 198023 : return GetTextNode()->GetText();
416 : }
417 :
418 17180 : void SwTextFrm::ResetPreps()
419 : {
420 17180 : if ( GetCacheIdx() != USHRT_MAX )
421 : {
422 : SwParaPortion *pPara;
423 17180 : if( 0 != (pPara = GetPara()) )
424 17178 : pPara->ResetPreps();
425 : }
426 17180 : }
427 :
428 578337 : bool SwTextFrm::IsHiddenNow() const
429 : {
430 578337 : SwFrmSwapper aSwapper( this, true );
431 :
432 578337 : if( !Frm().Width() && IsValid() && GetUpper()->IsValid() ) // invalid when stack overflows (StackHack)!
433 : {
434 : // OSL_FAIL( "SwTextFrm::IsHiddenNow: thin frame" );
435 2 : return true;
436 : }
437 :
438 578335 : const bool bHiddenCharsHidePara = GetTextNode()->HasHiddenCharAttribute( true );
439 578335 : const bool bHiddenParaField = GetTextNode()->HasHiddenParaField();
440 578335 : const SwViewShell* pVsh = getRootFrm()->GetCurrShell();
441 :
442 578335 : if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) )
443 : {
444 1004 : if (
445 0 : ( bHiddenParaField &&
446 0 : ( !pVsh->GetViewOptions()->IsShowHiddenPara() &&
447 3012 : !pVsh->GetViewOptions()->IsFieldName() ) ) ||
448 1004 : ( bHiddenCharsHidePara &&
449 1004 : !pVsh->GetViewOptions()->IsShowHiddenChar() ) )
450 : {
451 1004 : return true;
452 : }
453 : }
454 :
455 577331 : return false;
456 : }
457 :
458 : /// Removes Textfrm's attachments, when it's hidden
459 22 : void SwTextFrm::HideHidden()
460 : {
461 : OSL_ENSURE( !GetFollow() && IsHiddenNow(),
462 : "HideHidden on visible frame of hidden frame has follow" );
463 :
464 22 : const sal_Int32 nEnd = COMPLETE_STRING;
465 22 : HideFootnotes( GetOfst(), nEnd );
466 : // OD 2004-01-15 #110582#
467 22 : HideAndShowObjects();
468 :
469 : // format information is obsolete
470 22 : ClearPara();
471 22 : }
472 :
473 26 : void SwTextFrm::HideFootnotes( sal_Int32 nStart, sal_Int32 nEnd )
474 : {
475 26 : const SwpHints *pHints = GetTextNode()->GetpSwpHints();
476 26 : if( pHints )
477 : {
478 26 : const size_t nSize = pHints->Count();
479 26 : SwPageFrm *pPage = 0;
480 75 : for ( size_t i = 0; i < nSize; ++i )
481 : {
482 49 : const SwTextAttr *pHt = (*pHints)[i];
483 49 : if ( pHt->Which() == RES_TXTATR_FTN )
484 : {
485 0 : const sal_Int32 nIdx = pHt->GetStart();
486 0 : if ( nEnd < nIdx )
487 0 : break;
488 0 : if( nStart <= nIdx )
489 : {
490 0 : if( !pPage )
491 0 : pPage = FindPageFrm();
492 0 : pPage->RemoveFootnote( this, static_cast<const SwTextFootnote*>(pHt) );
493 : }
494 : }
495 : }
496 : }
497 26 : }
498 :
499 : /**
500 : * #120729# - hotfix
501 : * as-character anchored graphics, which are used for a graphic bullet list.
502 : * As long as these graphic bullet list aren't imported, do not hide a
503 : * at-character anchored object, if
504 : * (a) the document is an imported WW8 document -
505 : * checked by checking certain compatibility options -
506 : * (b) the paragraph is the last content in the document and
507 : * (c) the anchor character is an as-character anchored graphic.
508 : */
509 0 : bool sw_HideObj( const SwTextFrm& _rFrm,
510 : const RndStdIds _eAnchorType,
511 : const sal_Int32 _nObjAnchorPos,
512 : SwAnchoredObject* _pAnchoredObj )
513 : {
514 0 : bool bRet( true );
515 :
516 0 : if (_eAnchorType == FLY_AT_CHAR)
517 : {
518 0 : const IDocumentSettingAccess* pIDSA = _rFrm.GetTextNode()->getIDocumentSettingAccess();
519 0 : if ( !pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) &&
520 0 : !pIDSA->get(DocumentSettingId::OLD_LINE_SPACING) &&
521 0 : !pIDSA->get(DocumentSettingId::USE_FORMER_OBJECT_POS) &&
522 0 : pIDSA->get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
523 0 : _rFrm.IsInDocBody() && !_rFrm.FindNextCnt() )
524 : {
525 0 : const OUString &rStr = _rFrm.GetTextNode()->GetText();
526 0 : const sal_Unicode cAnchorChar = _nObjAnchorPos < rStr.getLength() ? rStr[_nObjAnchorPos] : 0;
527 0 : if (cAnchorChar == CH_TXTATR_BREAKWORD)
528 : {
529 : const SwTextAttr* const pHint(
530 : _rFrm.GetTextNode()->GetTextAttrForCharAt(_nObjAnchorPos,
531 0 : RES_TXTATR_FLYCNT) );
532 0 : if ( pHint )
533 : {
534 : const SwFrameFormat* pFrameFormat =
535 0 : static_cast<const SwTextFlyCnt*>(pHint)->GetFlyCnt().GetFrameFormat();
536 0 : if ( pFrameFormat->Which() == RES_FLYFRMFMT )
537 : {
538 0 : SwNodeIndex nContentIndex = *(pFrameFormat->GetContent().GetContentIdx());
539 0 : ++nContentIndex;
540 0 : if ( nContentIndex.GetNode().IsNoTextNode() )
541 : {
542 0 : bRet = false;
543 : // set needed data structure values for object positioning
544 0 : SWRECTFN( (&_rFrm) );
545 0 : SwRect aLastCharRect( _rFrm.Frm() );
546 0 : (aLastCharRect.*fnRect->fnSetWidth)( 1 );
547 0 : _pAnchoredObj->maLastCharRect = aLastCharRect;
548 0 : _pAnchoredObj->mnLastTopOfLine = (aLastCharRect.*fnRect->fnGetTop)();
549 0 : }
550 : }
551 : }
552 : }
553 : }
554 : }
555 :
556 0 : return bRet;
557 : }
558 :
559 : /**
560 : * Hide/show objects
561 : * OD 2004-01-15 #110582#
562 : *
563 : * Method hides respectively shows objects, which are anchored at paragraph,
564 : * at/as a character of the paragraph, corresponding to the paragraph and
565 : * paragraph portion visibility.
566 : *
567 : * - is called from HideHidden() - should hide objects in hidden paragraphs and
568 : * - from _Format() - should hide/show objects in partly visible paragraphs
569 : */
570 67440 : void SwTextFrm::HideAndShowObjects()
571 : {
572 67440 : if ( GetDrawObjs() )
573 : {
574 6703 : if ( IsHiddenNow() )
575 : {
576 : // complete paragraph is hidden. Thus, hide all objects
577 0 : for ( size_t i = 0; i < GetDrawObjs()->size(); ++i )
578 : {
579 0 : SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
580 0 : SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
581 : // #120729# - hotfix
582 : // under certain conditions
583 0 : const RndStdIds eAnchorType( pContact->GetAnchorId() );
584 0 : const sal_Int32 nObjAnchorPos = pContact->GetContentAnchorIndex().GetIndex();
585 0 : if ((eAnchorType != FLY_AT_CHAR) ||
586 : sw_HideObj( *this, eAnchorType, nObjAnchorPos,
587 0 : (*GetDrawObjs())[i] ))
588 : {
589 0 : pContact->MoveObjToInvisibleLayer( pObj );
590 : }
591 : }
592 : }
593 : else
594 : {
595 : // paragraph is visible, but can contain hidden text portion.
596 : // first we check if objects are allowed to be hidden:
597 6703 : const SwTextNode& rNode = *GetTextNode();
598 6703 : const SwViewShell* pVsh = getRootFrm()->GetCurrShell();
599 13406 : const bool bShouldBeHidden = !pVsh || !pVsh->GetWin() ||
600 13406 : !pVsh->GetViewOptions()->IsShowHiddenChar();
601 :
602 : // Thus, show all objects, which are anchored at paragraph and
603 : // hide/show objects, which are anchored at/as character, according
604 : // to the visibility of the anchor character.
605 65395 : for ( size_t i = 0; i < GetDrawObjs()->size(); ++i )
606 : {
607 58692 : SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
608 58692 : SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
609 : // #120729# - determine anchor type only once
610 58692 : const RndStdIds eAnchorType( pContact->GetAnchorId() );
611 :
612 58692 : if (eAnchorType == FLY_AT_PARA)
613 : {
614 55522 : pContact->MoveObjToVisibleLayer( pObj );
615 : }
616 3170 : else if ((eAnchorType == FLY_AT_CHAR) ||
617 : (eAnchorType == FLY_AS_CHAR))
618 : {
619 : sal_Int32 nHiddenStart;
620 : sal_Int32 nHiddenEnd;
621 3170 : const sal_Int32 nObjAnchorPos = pContact->GetContentAnchorIndex().GetIndex();
622 3170 : SwScriptInfo::GetBoundsOfHiddenRange( rNode, nObjAnchorPos, nHiddenStart, nHiddenEnd, 0 );
623 : // #120729# - hotfix
624 : // under certain conditions
625 3170 : if ( nHiddenStart != COMPLETE_STRING && bShouldBeHidden &&
626 0 : sw_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) )
627 0 : pContact->MoveObjToInvisibleLayer( pObj );
628 : else
629 3170 : pContact->MoveObjToVisibleLayer( pObj );
630 : }
631 : else
632 : {
633 : OSL_FAIL( "<SwTextFrm::HideAndShowObjects()> - object not anchored at/inside paragraph!?" );
634 : }
635 : }
636 : }
637 : }
638 :
639 67440 : if (IsFollow())
640 : {
641 3966 : SwTextFrm *pMaster = FindMaster();
642 : OSL_ENSURE(pMaster, "SwTextFrm without master");
643 3966 : if (pMaster)
644 3966 : pMaster->HideAndShowObjects();
645 : }
646 67440 : }
647 :
648 : /**
649 : * Returns the first possible break point in the current line.
650 : * This method is used in SwTextFrm::Format() to decide whether the previous
651 : * line has to be formatted as well.
652 : * nFound is <= nEndLine.
653 : */
654 1506 : sal_Int32 SwTextFrm::FindBrk( const OUString &rText,
655 : const sal_Int32 nStart,
656 : const sal_Int32 nEnd )
657 : {
658 1506 : sal_Int32 nFound = nStart;
659 1506 : const sal_Int32 nEndLine = std::min( nEnd, rText.getLength() - 1 );
660 :
661 : // skip all leading blanks (see bug #2235).
662 3015 : while( nFound <= nEndLine && ' ' == rText[nFound] )
663 : {
664 3 : nFound++;
665 : }
666 :
667 : // A tricky situation with the TextAttr-Dummy-character (in this case "$"):
668 : // "Dr.$Meyer" at the beginning of the second line. Typing a blank after that
669 : // doesn't result in the word moving into first line, even though that would work.
670 : // For this reason we don't skip the dummy char.
671 37677 : while( nFound <= nEndLine && ' ' != rText[nFound] )
672 : {
673 34665 : nFound++;
674 : }
675 :
676 1506 : return nFound;
677 : }
678 :
679 21149 : bool SwTextFrm::IsIdxInside( const sal_Int32 nPos, const sal_Int32 nLen ) const
680 : {
681 21149 : if( nLen != COMPLETE_STRING && GetOfst() > nPos + nLen ) // the range preceded us
682 205 : return false;
683 :
684 20944 : if( !GetFollow() ) // the range doesn't precede us,
685 19938 : return true; // nobody follows us.
686 :
687 1006 : const sal_Int32 nMax = GetFollow()->GetOfst();
688 :
689 : // either the range overlap or our text has been deleted
690 1006 : if( nMax > nPos || nMax > GetText().getLength() )
691 285 : return true;
692 :
693 : // changes made in the first line of a follow can modify the master
694 721 : const SwParaPortion* pPara = GetFollow()->GetPara();
695 721 : return pPara && ( nPos <= nMax + pPara->GetLen() );
696 : }
697 :
698 6668 : inline void SwTextFrm::InvalidateRange(const SwCharRange &aRange, const long nD)
699 : {
700 6668 : if ( IsIdxInside( aRange.Start(), aRange.Len() ) )
701 6644 : _InvalidateRange( aRange, nD );
702 6668 : }
703 :
704 19600 : void SwTextFrm::_InvalidateRange( const SwCharRange &aRange, const long nD)
705 : {
706 19600 : if ( !HasPara() )
707 7893 : { InvalidateSize();
708 27493 : return;
709 : }
710 :
711 11707 : SetWidow( false );
712 11707 : SwParaPortion *pPara = GetPara();
713 :
714 11707 : bool bInv = false;
715 11707 : if( 0 != nD )
716 : {
717 : // In nDelta the differences between old and new
718 : // linelengths are being added, that's why it's negative
719 : // if chars have been added and positive, if chars have
720 : // deleted
721 6758 : pPara->GetDelta() += nD;
722 6758 : bInv = true;
723 : }
724 11707 : SwCharRange &rReformat = pPara->GetReformat();
725 11707 : if(aRange != rReformat) {
726 9678 : if( COMPLETE_STRING == rReformat.Len() )
727 0 : rReformat = aRange;
728 : else
729 9678 : rReformat += aRange;
730 9678 : bInv = true;
731 : }
732 11707 : if(bInv)
733 : {
734 9800 : InvalidateSize();
735 : }
736 : }
737 :
738 69 : void SwTextFrm::CalcLineSpace()
739 : {
740 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
741 : "SwTextFrm::CalcLineSpace with swapped frame!" );
742 :
743 69 : if( IsLocked() || !HasPara() )
744 134 : return;
745 :
746 : SwParaPortion *pPara;
747 6 : if( GetDrawObjs() ||
748 6 : GetTextNode()->GetSwAttrSet().GetLRSpace().IsAutoFirst() ||
749 2 : ( pPara = GetPara() )->IsFixLineHeight() )
750 : {
751 0 : Init();
752 0 : return;
753 : }
754 :
755 2 : Size aNewSize( Prt().SSize() );
756 :
757 2 : SwTextFormatInfo aInf( this );
758 4 : SwTextFormatter aLine( this, &aInf );
759 2 : if( aLine.GetDropLines() )
760 : {
761 0 : Init();
762 0 : return;
763 : }
764 :
765 2 : aLine.Top();
766 2 : aLine.RecalcRealHeight();
767 :
768 2 : aNewSize.Height() = (aLine.Y() - Frm().Top()) + aLine.GetLineHeight();
769 :
770 2 : SwTwips nDelta = aNewSize.Height() - Prt().Height();
771 : // Underflow with free-flying frames
772 2 : if( aInf.GetTextFly().IsOn() )
773 : {
774 0 : SwRect aTmpFrm( Frm() );
775 0 : if( nDelta < 0 )
776 0 : aTmpFrm.Height( Prt().Height() );
777 : else
778 0 : aTmpFrm.Height( aNewSize.Height() );
779 0 : if( aInf.GetTextFly().Relax( aTmpFrm ) )
780 : {
781 0 : Init();
782 0 : return;
783 : }
784 : }
785 :
786 2 : if( nDelta )
787 : {
788 0 : SwTextFrmBreak aBreak( this );
789 0 : if( GetFollow() || aBreak.IsBreakNow( aLine ) )
790 : {
791 : // if there is a Follow() or if we need to break here, reformat
792 0 : Init();
793 : }
794 : else
795 : {
796 : // everything is business as usual...
797 0 : pPara->SetPrepAdjust();
798 0 : pPara->SetPrep();
799 : }
800 2 : }
801 : }
802 :
803 13155 : static void lcl_SetWrong( SwTextFrm& rFrm, sal_Int32 nPos, sal_Int32 nCnt, bool bMove )
804 : {
805 13155 : if ( !rFrm.IsFollow() )
806 : {
807 12239 : SwTextNode* pTextNode = rFrm.GetTextNode();
808 12239 : IGrammarContact* pGrammarContact = getGrammarContact( *pTextNode );
809 : SwGrammarMarkUp* pWrongGrammar = pGrammarContact ?
810 12239 : pGrammarContact->getGrammarCheck( *pTextNode, false ) :
811 24478 : pTextNode->GetGrammarCheck();
812 12239 : bool bGrammarProxy = pWrongGrammar != pTextNode->GetGrammarCheck();
813 12239 : if( bMove )
814 : {
815 9485 : if( pTextNode->GetWrong() )
816 268 : pTextNode->GetWrong()->Move( nPos, nCnt );
817 9485 : if( pWrongGrammar )
818 0 : pWrongGrammar->MoveGrammar( nPos, nCnt );
819 9485 : if( bGrammarProxy && pTextNode->GetGrammarCheck() )
820 0 : pTextNode->GetGrammarCheck()->MoveGrammar( nPos, nCnt );
821 9485 : if( pTextNode->GetSmartTags() )
822 0 : pTextNode->GetSmartTags()->Move( nPos, nCnt );
823 : }
824 : else
825 : {
826 2754 : if( pTextNode->GetWrong() )
827 67 : pTextNode->GetWrong()->Invalidate( nPos, nCnt );
828 2754 : if( pWrongGrammar )
829 0 : pWrongGrammar->Invalidate( nPos, nCnt );
830 2754 : if( pTextNode->GetSmartTags() )
831 0 : pTextNode->GetSmartTags()->Invalidate( nPos, nCnt );
832 : }
833 12239 : const sal_Int32 nEnd = nPos + (nCnt > 0 ? nCnt : 1 );
834 12239 : if ( !pTextNode->GetWrong() && !pTextNode->IsWrongDirty() )
835 : {
836 4071 : pTextNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
837 4071 : pTextNode->GetWrong()->SetInvalid( nPos, nEnd );
838 : }
839 12239 : if ( !pTextNode->GetSmartTags() && !pTextNode->IsSmartTagDirty() )
840 : {
841 0 : pTextNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) );
842 0 : pTextNode->GetSmartTags()->SetInvalid( nPos, nEnd );
843 : }
844 12239 : pTextNode->SetWrongDirty( true );
845 12239 : pTextNode->SetGrammarCheckDirty( true );
846 12239 : pTextNode->SetWordCountDirty( true );
847 12239 : pTextNode->SetAutoCompleteWordDirty( true );
848 12239 : pTextNode->SetSmartTagDirty( true );
849 : }
850 :
851 13155 : SwRootFrm *pRootFrm = rFrm.getRootFrm();
852 13155 : if (pRootFrm)
853 : {
854 13155 : pRootFrm->SetNeedGrammarCheck( true );
855 : }
856 :
857 13155 : SwPageFrm *pPage = rFrm.FindPageFrm();
858 13155 : if( pPage )
859 : {
860 13155 : pPage->InvalidateSpelling();
861 13155 : pPage->InvalidateAutoCompleteWords();
862 13155 : pPage->InvalidateWordCount();
863 13155 : pPage->InvalidateSmartTags();
864 : }
865 13155 : }
866 :
867 14339 : static void lcl_SetScriptInval( SwTextFrm& rFrm, sal_Int32 nPos )
868 : {
869 14339 : if( rFrm.GetPara() )
870 5419 : rFrm.GetPara()->GetScriptInfo().SetInvalidityA( nPos );
871 14339 : }
872 :
873 916 : static void lcl_ModifyOfst( SwTextFrm* pFrm, sal_Int32 nPos, sal_Int32 nLen )
874 : {
875 3574 : while( pFrm && pFrm->GetOfst() <= nPos )
876 1742 : pFrm = pFrm->GetFollow();
877 2293 : while( pFrm )
878 : {
879 461 : if (nLen == COMPLETE_STRING)
880 21 : pFrm->ManipOfst( pFrm->GetTextNode()->GetText().getLength() );
881 : else
882 440 : pFrm->ManipOfst( pFrm->GetOfst() + nLen );
883 461 : pFrm = pFrm->GetFollow();
884 : }
885 916 : }
886 :
887 : /**
888 : * Related: fdo#56031 filter out attribute changes that don't matter for
889 : * humans/a11y to stop flooding the destination mortal with useless noise
890 : */
891 7515 : static bool isA11yRelevantAttribute(sal_uInt16 nWhich)
892 : {
893 7515 : return nWhich != RES_CHRATR_RSID;
894 : }
895 :
896 3036 : static bool hasA11yRelevantAttribute( const std::vector<sal_uInt16>& nWhich )
897 : {
898 9108 : for( std::vector<sal_uInt16>::const_iterator nItr = nWhich.begin();
899 6072 : nItr < nWhich.end(); ++nItr )
900 0 : if ( isA11yRelevantAttribute( *nItr ) )
901 0 : return true;
902 :
903 3036 : return false;
904 : }
905 :
906 22038 : void SwTextFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
907 : {
908 22038 : const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
909 :
910 : // modifications concerning frame attributes are processed by the base class
911 22038 : if( IsInRange( aFrameFormatSetRange, nWhich ) || RES_FMT_CHG == nWhich )
912 : {
913 2137 : SwContentFrm::Modify( pOld, pNew );
914 2137 : if( nWhich == RES_FMT_CHG && getRootFrm()->GetCurrShell() )
915 : {
916 : // collection has changed
917 262 : Prepare( PREP_CLEAR );
918 262 : _InvalidatePrt();
919 262 : lcl_SetWrong( *this, 0, COMPLETE_STRING, false );
920 262 : SetDerivedR2L( false );
921 262 : CheckDirChange();
922 : // OD 09.12.2002 #105576# - Force complete paint due to existing
923 : // indents.
924 262 : SetCompletePaint();
925 262 : InvalidateLineNum();
926 : }
927 2137 : return;
928 : }
929 :
930 : // while locked ignore all modifications
931 19901 : if( IsLocked() )
932 0 : return;
933 :
934 : // save stack
935 : // warning: one has to ensure that all variables are set
936 : sal_Int32 nPos;
937 : sal_Int32 nLen;
938 19901 : bool bSetFieldsDirty = false;
939 19901 : bool bRecalcFootnoteFlag = false;
940 :
941 19901 : switch( nWhich )
942 : {
943 : case RES_LINENUMBER:
944 : {
945 0 : InvalidateLineNum();
946 : }
947 0 : break;
948 : case RES_INS_TXT:
949 : {
950 9170 : nPos = static_cast<const SwInsText*>(pNew)->nPos;
951 9170 : nLen = static_cast<const SwInsText*>(pNew)->nLen;
952 9170 : if( IsIdxInside( nPos, nLen ) )
953 : {
954 8684 : if( !nLen )
955 : {
956 : // Refresh NumPortions even when line is empty!
957 0 : if( nPos )
958 0 : InvalidateSize();
959 : else
960 0 : Prepare( PREP_CLEAR );
961 : }
962 : else
963 8684 : _InvalidateRange( SwCharRange( nPos, nLen ), nLen );
964 : }
965 9170 : lcl_SetWrong( *this, nPos, nLen, true );
966 9170 : lcl_SetScriptInval( *this, nPos );
967 9170 : bSetFieldsDirty = true;
968 9170 : if( HasFollow() )
969 499 : lcl_ModifyOfst( this, nPos, nLen );
970 : }
971 9170 : break;
972 : case RES_DEL_CHR:
973 : {
974 234 : nPos = static_cast<const SwDelChr*>(pNew)->nPos;
975 234 : InvalidateRange( SwCharRange( nPos, 1 ), -1 );
976 234 : lcl_SetWrong( *this, nPos, -1, true );
977 234 : lcl_SetScriptInval( *this, nPos );
978 234 : bSetFieldsDirty = bRecalcFootnoteFlag = true;
979 234 : if( HasFollow() )
980 23 : lcl_ModifyOfst( this, nPos, COMPLETE_STRING );
981 : }
982 234 : break;
983 : case RES_DEL_TXT:
984 : {
985 997 : nPos = static_cast<const SwDelText*>(pNew)->nStart;
986 997 : nLen = static_cast<const SwDelText*>(pNew)->nLen;
987 997 : const sal_Int32 m = -nLen;
988 997 : if( IsIdxInside( nPos, nLen ) )
989 : {
990 608 : if( !nLen )
991 26 : InvalidateSize();
992 : else
993 582 : InvalidateRange( SwCharRange( nPos, 1 ), m );
994 : }
995 997 : lcl_SetWrong( *this, nPos, m, true );
996 997 : lcl_SetScriptInval( *this, nPos );
997 997 : bSetFieldsDirty = bRecalcFootnoteFlag = true;
998 997 : if( HasFollow() )
999 394 : lcl_ModifyOfst( this, nPos, nLen );
1000 : }
1001 997 : break;
1002 : case RES_UPDATE_ATTR:
1003 : {
1004 3036 : nPos = static_cast<const SwUpdateAttr*>(pNew)->getStart();
1005 3036 : nLen = static_cast<const SwUpdateAttr*>(pNew)->getEnd() - nPos;
1006 3036 : if( IsIdxInside( nPos, nLen ) )
1007 : {
1008 : // We need to reformat anyways, even if the invalidated
1009 : // area is NULL.
1010 : // E.g.: empty line, set 14 pt!
1011 : // if( !nLen ) nLen = 1;
1012 :
1013 : // FootnoteNummbers need to be formatted
1014 3036 : if( !nLen )
1015 747 : nLen = 1;
1016 :
1017 3036 : _InvalidateRange( SwCharRange( nPos, nLen) );
1018 3036 : const sal_uInt16 nTmp = static_cast<const SwUpdateAttr*>(pNew)->getWhichAttr();
1019 :
1020 3036 : if( ! nTmp || RES_TXTATR_CHARFMT == nTmp || RES_TXTATR_AUTOFMT == nTmp ||
1021 814 : RES_FMT_CHG == nTmp || RES_ATTRSET_CHG == nTmp )
1022 : {
1023 2355 : lcl_SetWrong( *this, nPos, nPos + nLen, false );
1024 2355 : lcl_SetScriptInval( *this, nPos );
1025 : }
1026 : }
1027 :
1028 6072 : if( isA11yRelevantAttribute( static_cast<const SwUpdateAttr*>(pNew)->getWhichAttr() ) &&
1029 3036 : hasA11yRelevantAttribute( static_cast<const SwUpdateAttr*>(pNew)->getFormatAttr() ) )
1030 : {
1031 : // #i104008#
1032 0 : SwViewShell* pViewSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
1033 0 : if ( pViewSh )
1034 : {
1035 0 : pViewSh->InvalidateAccessibleParaAttrs( *this );
1036 : }
1037 : }
1038 : }
1039 3036 : break;
1040 : case RES_OBJECTDYING:
1041 0 : break;
1042 :
1043 : case RES_PARATR_LINESPACING:
1044 : {
1045 0 : CalcLineSpace();
1046 0 : InvalidateSize();
1047 0 : _InvalidatePrt();
1048 0 : if( IsInSct() && !GetPrev() )
1049 : {
1050 0 : SwSectionFrm *pSect = FindSctFrm();
1051 0 : if( pSect->ContainsAny() == this )
1052 0 : pSect->InvalidatePrt();
1053 : }
1054 :
1055 : // OD 09.01.2004 #i11859# - correction:
1056 : // (1) Also invalidate next frame on next page/column.
1057 : // (2) Skip empty sections and hidden paragraphs
1058 : // Thus, use method <InvalidateNextPrtArea()>
1059 0 : InvalidateNextPrtArea();
1060 :
1061 0 : SetCompletePaint();
1062 : }
1063 0 : break;
1064 :
1065 : case RES_TXTATR_FIELD:
1066 : case RES_TXTATR_ANNOTATION:
1067 : {
1068 1225 : nPos = static_cast<const SwFormatField*>(pNew)->GetTextField()->GetStart();
1069 1225 : if( IsIdxInside( nPos, 1 ) )
1070 : {
1071 1225 : if( pNew == pOld )
1072 : {
1073 : // only repaint
1074 : // opt: invalidate window?
1075 0 : InvalidatePage();
1076 0 : SetCompletePaint();
1077 : }
1078 : else
1079 1225 : _InvalidateRange( SwCharRange( nPos, 1 ) );
1080 : }
1081 1225 : bSetFieldsDirty = true;
1082 : // ST2
1083 1225 : if ( SwSmartTagMgr::Get().IsSmartTagsEnabled() )
1084 0 : lcl_SetWrong( *this, nPos, nPos + 1, false );
1085 : }
1086 1225 : break;
1087 :
1088 : case RES_TXTATR_FTN :
1089 : {
1090 77 : nPos = static_cast<const SwFormatFootnote*>(pNew)->GetTextFootnote()->GetStart();
1091 77 : if( IsInFootnote() || IsIdxInside( nPos, 1 ) )
1092 77 : Prepare( PREP_FTN, static_cast<const SwFormatFootnote*>(pNew)->GetTextFootnote() );
1093 77 : break;
1094 : }
1095 :
1096 : case RES_ATTRSET_CHG:
1097 : {
1098 4479 : InvalidateLineNum();
1099 :
1100 4479 : const SwAttrSet& rNewSet = *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
1101 4479 : const SfxPoolItem* pItem = 0;
1102 4479 : int nClear = 0;
1103 4479 : sal_uInt16 nCount = rNewSet.Count();
1104 :
1105 4479 : if( SfxItemState::SET == rNewSet.GetItemState( RES_TXTATR_FTN, false, &pItem ))
1106 : {
1107 0 : nPos = static_cast<const SwFormatFootnote*>(pItem)->GetTextFootnote()->GetStart();
1108 0 : if( IsIdxInside( nPos, 1 ) )
1109 0 : Prepare( PREP_FTN, pNew );
1110 0 : nClear = 0x01;
1111 0 : --nCount;
1112 : }
1113 :
1114 4479 : if( SfxItemState::SET == rNewSet.GetItemState( RES_TXTATR_FIELD, false, &pItem ))
1115 : {
1116 0 : nPos = static_cast<const SwFormatField*>(pItem)->GetTextField()->GetStart();
1117 0 : if( IsIdxInside( nPos, 1 ) )
1118 : {
1119 : const SfxPoolItem* pOldItem = pOld ?
1120 0 : &(static_cast<const SwAttrSetChg*>(pOld)->GetChgSet()->Get(RES_TXTATR_FIELD)) : NULL;
1121 0 : if( pItem == pOldItem )
1122 : {
1123 0 : InvalidatePage();
1124 0 : SetCompletePaint();
1125 : }
1126 : else
1127 0 : _InvalidateRange( SwCharRange( nPos, 1 ) );
1128 : }
1129 0 : nClear |= 0x02;
1130 0 : --nCount;
1131 : }
1132 : bool bLineSpace = SfxItemState::SET == rNewSet.GetItemState(
1133 4479 : RES_PARATR_LINESPACING, false ),
1134 : bRegister = SfxItemState::SET == rNewSet.GetItemState(
1135 4479 : RES_PARATR_REGISTER, false );
1136 4479 : if ( bLineSpace || bRegister )
1137 : {
1138 69 : Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
1139 69 : CalcLineSpace();
1140 69 : InvalidateSize();
1141 69 : _InvalidatePrt();
1142 :
1143 : // OD 09.01.2004 #i11859# - correction:
1144 : // (1) Also invalidate next frame on next page/column.
1145 : // (2) Skip empty sections and hidden paragraphs
1146 : // Thus, use method <InvalidateNextPrtArea()>
1147 69 : InvalidateNextPrtArea();
1148 :
1149 69 : SetCompletePaint();
1150 69 : nClear |= 0x04;
1151 69 : if ( bLineSpace )
1152 : {
1153 69 : --nCount;
1154 69 : if( IsInSct() && !GetPrev() )
1155 : {
1156 0 : SwSectionFrm *pSect = FindSctFrm();
1157 0 : if( pSect->ContainsAny() == this )
1158 0 : pSect->InvalidatePrt();
1159 : }
1160 : }
1161 69 : if ( bRegister )
1162 0 : --nCount;
1163 : }
1164 4479 : if ( SfxItemState::SET == rNewSet.GetItemState( RES_PARATR_SPLIT,
1165 4479 : false ))
1166 : {
1167 0 : if ( GetPrev() )
1168 0 : CheckKeep();
1169 0 : Prepare( PREP_CLEAR );
1170 0 : InvalidateSize();
1171 0 : nClear |= 0x08;
1172 0 : --nCount;
1173 : }
1174 :
1175 8958 : if( SfxItemState::SET == rNewSet.GetItemState( RES_BACKGROUND, false)
1176 4479 : && !IsFollow() && GetDrawObjs() )
1177 : {
1178 0 : SwSortedObjs *pObjs = GetDrawObjs();
1179 0 : for ( size_t i = 0; GetDrawObjs() && i < pObjs->size(); ++i )
1180 : {
1181 0 : SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
1182 0 : if ( pAnchoredObj->ISA(SwFlyFrm) )
1183 : {
1184 0 : SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
1185 0 : if( !pFly->IsFlyInCntFrm() )
1186 : {
1187 : const SvxBrushItem &rBack =
1188 0 : pFly->GetAttrSet()->GetBackground();
1189 : // OD 20.08.2002 #99657# #GetTransChg#
1190 : // following condition determines, if the fly frame
1191 : // "inherites" the background color of text frame.
1192 : // This is the case, if fly frame background
1193 : // color is "no fill"/"auto fill" and if the fly frame
1194 : // has no background graphic.
1195 : // Thus, check complete fly frame background
1196 : // color and *not* only its transparency value
1197 0 : if ( (rBack.GetColor() == COL_TRANSPARENT) &&
1198 0 : rBack.GetGraphicPos() == GPOS_NONE )
1199 : {
1200 0 : pFly->SetCompletePaint();
1201 0 : pFly->InvalidatePage();
1202 : }
1203 : }
1204 : }
1205 : }
1206 : }
1207 :
1208 4479 : if ( SfxItemState::SET ==
1209 4479 : rNewSet.GetItemState( RES_TXTATR_CHARFMT, false ) )
1210 : {
1211 0 : lcl_SetWrong( *this, 0, COMPLETE_STRING, false );
1212 0 : lcl_SetScriptInval( *this, 0 );
1213 : }
1214 4479 : else if ( SfxItemState::SET ==
1215 8872 : rNewSet.GetItemState( RES_CHRATR_LANGUAGE, false ) ||
1216 : SfxItemState::SET ==
1217 8843 : rNewSet.GetItemState( RES_CHRATR_CJK_LANGUAGE, false ) ||
1218 : SfxItemState::SET ==
1219 4364 : rNewSet.GetItemState( RES_CHRATR_CTL_LANGUAGE, false ) )
1220 137 : lcl_SetWrong( *this, 0, COMPLETE_STRING, false );
1221 4342 : else if ( SfxItemState::SET ==
1222 7323 : rNewSet.GetItemState( RES_CHRATR_FONT, false ) ||
1223 : SfxItemState::SET ==
1224 7211 : rNewSet.GetItemState( RES_CHRATR_CJK_FONT, false ) ||
1225 : SfxItemState::SET ==
1226 2869 : rNewSet.GetItemState( RES_CHRATR_CTL_FONT, false ) )
1227 1583 : lcl_SetScriptInval( *this, 0 );
1228 2759 : else if ( SfxItemState::SET ==
1229 2759 : rNewSet.GetItemState( RES_FRAMEDIR, false ) )
1230 : {
1231 182 : SetDerivedR2L( false );
1232 182 : CheckDirChange();
1233 : // OD 09.12.2002 #105576# - Force complete paint due to existing
1234 : // indents.
1235 182 : SetCompletePaint();
1236 : }
1237 :
1238 4479 : if( nCount )
1239 : {
1240 4479 : if( getRootFrm()->GetCurrShell() )
1241 : {
1242 4479 : Prepare( PREP_CLEAR );
1243 4479 : _InvalidatePrt();
1244 : }
1245 :
1246 4479 : if( nClear )
1247 : {
1248 69 : SwAttrSetChg aOldSet( *static_cast<const SwAttrSetChg*>(pOld) );
1249 138 : SwAttrSetChg aNewSet( *static_cast<const SwAttrSetChg*>(pNew) );
1250 :
1251 69 : if( 0x01 & nClear )
1252 : {
1253 0 : aOldSet.ClearItem( RES_TXTATR_FTN );
1254 0 : aNewSet.ClearItem( RES_TXTATR_FTN );
1255 : }
1256 69 : if( 0x02 & nClear )
1257 : {
1258 0 : aOldSet.ClearItem( RES_TXTATR_FIELD );
1259 0 : aNewSet.ClearItem( RES_TXTATR_FIELD );
1260 : }
1261 69 : if ( 0x04 & nClear )
1262 : {
1263 69 : if ( bLineSpace )
1264 : {
1265 69 : aOldSet.ClearItem( RES_PARATR_LINESPACING );
1266 69 : aNewSet.ClearItem( RES_PARATR_LINESPACING );
1267 : }
1268 69 : if ( bRegister )
1269 : {
1270 0 : aOldSet.ClearItem( RES_PARATR_REGISTER );
1271 0 : aNewSet.ClearItem( RES_PARATR_REGISTER );
1272 : }
1273 : }
1274 69 : if ( 0x08 & nClear )
1275 : {
1276 0 : aOldSet.ClearItem( RES_PARATR_SPLIT );
1277 0 : aNewSet.ClearItem( RES_PARATR_SPLIT );
1278 : }
1279 138 : SwContentFrm::Modify( &aOldSet, &aNewSet );
1280 : }
1281 : else
1282 4410 : SwContentFrm::Modify( pOld, pNew );
1283 : }
1284 :
1285 4479 : if (isA11yRelevantAttribute(nWhich))
1286 : {
1287 : // #i88069#
1288 4479 : SwViewShell* pViewSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
1289 4479 : if ( pViewSh )
1290 : {
1291 4479 : pViewSh->InvalidateAccessibleParaAttrs( *this );
1292 : }
1293 : }
1294 : }
1295 4479 : break;
1296 :
1297 : // Process SwDocPosUpdate
1298 : case RES_DOCPOS_UPDATE:
1299 : {
1300 678 : if( pOld && pNew )
1301 : {
1302 678 : const SwDocPosUpdate *pDocPos = static_cast<const SwDocPosUpdate*>(pOld);
1303 678 : if( pDocPos->nDocPos <= maFrm.Top() )
1304 : {
1305 648 : const SwFormatField *pField = static_cast<const SwFormatField *>(pNew);
1306 : InvalidateRange(
1307 648 : SwCharRange( pField->GetTextField()->GetStart(), 1 ) );
1308 : }
1309 : }
1310 678 : break;
1311 : }
1312 : case RES_PARATR_SPLIT:
1313 0 : if ( GetPrev() )
1314 0 : CheckKeep();
1315 0 : Prepare( PREP_CLEAR );
1316 0 : bSetFieldsDirty = true;
1317 0 : break;
1318 : case RES_FRAMEDIR :
1319 0 : SetDerivedR2L( false );
1320 0 : CheckDirChange();
1321 0 : break;
1322 : default:
1323 : {
1324 5 : Prepare( PREP_CLEAR );
1325 5 : _InvalidatePrt();
1326 5 : if ( !nWhich )
1327 : {
1328 : // is called by e. g. HiddenPara with 0
1329 : SwFrm *pNxt;
1330 0 : if ( 0 != (pNxt = FindNext()) )
1331 0 : pNxt->InvalidatePrt();
1332 : }
1333 : }
1334 : } // switch
1335 :
1336 19901 : if( bSetFieldsDirty )
1337 11626 : GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( true, GetNode(), 1 );
1338 :
1339 19901 : if ( bRecalcFootnoteFlag )
1340 1231 : CalcFootnoteFlag();
1341 : }
1342 :
1343 1197 : bool SwTextFrm::GetInfo( SfxPoolItem &rHint ) const
1344 : {
1345 1197 : if ( RES_VIRTPAGENUM_INFO == rHint.Which() && IsInDocBody() && ! IsFollow() )
1346 : {
1347 1197 : SwVirtPageNumInfo &rInfo = static_cast<SwVirtPageNumInfo&>(rHint);
1348 1197 : const SwPageFrm *pPage = FindPageFrm();
1349 1197 : if ( pPage )
1350 : {
1351 1197 : if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
1352 : {
1353 : // this should be the one
1354 : // (could only differ temporarily; is that disturbing?)
1355 220 : rInfo.SetInfo( pPage, this );
1356 220 : return false;
1357 : }
1358 2477 : if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
1359 750 : (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
1360 : {
1361 : // this could be the one
1362 750 : rInfo.SetInfo( pPage, this );
1363 : }
1364 : }
1365 : }
1366 977 : return true;
1367 : }
1368 :
1369 170 : void SwTextFrm::PrepWidows( const sal_uInt16 nNeed, bool bNotify )
1370 : {
1371 : OSL_ENSURE(GetFollow() && nNeed, "+SwTextFrm::Prepare: lost all friends");
1372 :
1373 170 : SwParaPortion *pPara = GetPara();
1374 170 : if ( !pPara )
1375 170 : return;
1376 170 : pPara->SetPrepWidows();
1377 :
1378 170 : sal_uInt16 nHave = nNeed;
1379 :
1380 : // We yield a few lines and shrink in CalcPreps()
1381 170 : SWAP_IF_NOT_SWAPPED swap( this );
1382 :
1383 340 : SwTextSizeInfo aInf( this );
1384 340 : SwTextMargin aLine( this, &aInf );
1385 170 : aLine.Bottom();
1386 170 : sal_Int32 nTmpLen = aLine.GetCurr()->GetLen();
1387 484 : while( nHave && aLine.PrevLine() )
1388 : {
1389 144 : if( nTmpLen )
1390 144 : --nHave;
1391 144 : nTmpLen = aLine.GetCurr()->GetLen();
1392 : }
1393 :
1394 : // If it's certain that we can yield lines, the Master needs
1395 : // to check the widow rule
1396 170 : if( !nHave )
1397 : {
1398 144 : bool bSplit = true;
1399 144 : if( !IsFollow() ) // only a master decides about orphans
1400 : {
1401 138 : const WidowsAndOrphans aWidOrp( this );
1402 158 : bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() &&
1403 158 : aLine.GetLineNr() >= aLine.GetDropLines() );
1404 : }
1405 :
1406 144 : if( bSplit )
1407 : {
1408 26 : GetFollow()->SetOfst( aLine.GetEnd() );
1409 26 : aLine.TruncLines( true );
1410 26 : if( pPara->IsFollowField() )
1411 0 : GetFollow()->SetFieldFollow( true );
1412 : }
1413 : }
1414 170 : if ( bNotify )
1415 : {
1416 170 : _InvalidateSize();
1417 170 : InvalidatePage();
1418 170 : }
1419 : }
1420 :
1421 129 : static bool lcl_ErgoVadis( SwTextFrm* pFrm, sal_Int32 &rPos, const PrepareHint ePrep )
1422 : {
1423 129 : const SwFootnoteInfo &rFootnoteInfo = pFrm->GetNode()->GetDoc()->GetFootnoteInfo();
1424 129 : if( ePrep == PREP_ERGOSUM )
1425 : {
1426 52 : if( rFootnoteInfo.aErgoSum.isEmpty() )
1427 52 : return false;
1428 0 : rPos = pFrm->GetOfst();
1429 : }
1430 : else
1431 : {
1432 77 : if( rFootnoteInfo.aQuoVadis.isEmpty() )
1433 77 : return false;
1434 0 : if( pFrm->HasFollow() )
1435 0 : rPos = pFrm->GetFollow()->GetOfst();
1436 : else
1437 0 : rPos = pFrm->GetText().getLength();
1438 0 : if( rPos )
1439 0 : --rPos; // our last character
1440 : }
1441 0 : return true;
1442 : }
1443 :
1444 192049 : bool SwTextFrm::Prepare( const PrepareHint ePrep, const void* pVoid,
1445 : bool bNotify )
1446 : {
1447 192049 : bool bParaPossiblyInvalid = false;
1448 :
1449 192049 : SwFrmSwapper aSwapper( this, false );
1450 :
1451 : #if OSL_DEBUG_LEVEL > 1
1452 : const SwTwips nDbgY = Frm().Top();
1453 : (void)nDbgY;
1454 : #endif
1455 :
1456 192049 : if ( IsEmpty() )
1457 : {
1458 16029 : switch ( ePrep )
1459 : {
1460 : case PREP_BOSS_CHGD:
1461 2060 : SetInvalidVert( true ); // Test
1462 : case PREP_WIDOWS_ORPHANS:
1463 : case PREP_WIDOWS:
1464 2184 : case PREP_FTN_GONE : return bParaPossiblyInvalid;
1465 :
1466 : case PREP_POS_CHGD :
1467 : {
1468 : // We also need an InvalidateSize for Areas (with and without columns),
1469 : // so that we format and bUndersized is set (if needed)
1470 4717 : if( IsInFly() || IsInSct() )
1471 : {
1472 476 : SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1473 476 : GetUpper()->Prt().Bottom();
1474 476 : if( nTmpBottom < Frm().Bottom() )
1475 449 : break;
1476 : }
1477 : // Are there any free-flying frames on this page?
1478 4568 : SwTextFly aTextFly( this );
1479 4568 : if( aTextFly.IsOn() )
1480 : {
1481 : // Does any free-flying frame overlap?
1482 735 : if ( aTextFly.Relax() || IsUndersized() )
1483 130 : break;
1484 : }
1485 4438 : if( GetTextNode()->GetSwAttrSet().GetRegister().GetValue())
1486 0 : break;
1487 :
1488 4438 : SwTextGridItem const*const pGrid(GetGridItem(FindPageFrm()));
1489 4438 : if ( pGrid && GetTextNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1490 0 : break;
1491 :
1492 : // #i28701# - consider anchored objects
1493 4438 : if ( GetDrawObjs() )
1494 21 : break;
1495 :
1496 4417 : return bParaPossiblyInvalid;
1497 : }
1498 : default:
1499 9128 : break;
1500 : }
1501 : }
1502 :
1503 185448 : if( !HasPara() && PREP_MUST_FIT != ePrep )
1504 : {
1505 145444 : SetInvalidVert( true ); // Test
1506 : OSL_ENSURE( !IsLocked(), "SwTextFrm::Prepare: three of a perfect pair" );
1507 145444 : if ( bNotify )
1508 106344 : InvalidateSize();
1509 : else
1510 39100 : _InvalidateSize();
1511 145444 : return bParaPossiblyInvalid;
1512 : }
1513 :
1514 : // Get object from cache while locking
1515 40004 : SwTextLineAccess aAccess( this );
1516 40004 : SwParaPortion *pPara = aAccess.GetPara();
1517 :
1518 40004 : switch( ePrep )
1519 : {
1520 10 : case PREP_MOVEFTN : Frm().Height(0);
1521 10 : Prt().Height(0);
1522 10 : _InvalidatePrt();
1523 10 : _InvalidateSize();
1524 : /* no break here */
1525 9530 : case PREP_ADJUST_FRM : pPara->SetPrepAdjust();
1526 19057 : if( IsFootnoteNumFrm() != pPara->IsFootnoteNum() ||
1527 9527 : IsUndersized() )
1528 : {
1529 2272 : InvalidateRange( SwCharRange( 0, 1 ), 1);
1530 2272 : if( GetOfst() && !IsFollow() )
1531 0 : _SetOfst( 0 );
1532 : }
1533 9530 : break;
1534 221 : case PREP_MUST_FIT : pPara->SetPrepMustFit();
1535 : /* no break here */
1536 1418 : case PREP_WIDOWS_ORPHANS : pPara->SetPrepAdjust();
1537 1418 : break;
1538 :
1539 : case PREP_WIDOWS :
1540 : // MustFit is stronger than anything else
1541 170 : if( pPara->IsPrepMustFit() )
1542 0 : return bParaPossiblyInvalid;
1543 : // see comment in WidowsAndOrphans::FindOrphans and CalcPreps()
1544 170 : PrepWidows( *static_cast<const sal_uInt16 *>(pVoid), bNotify );
1545 170 : break;
1546 :
1547 : case PREP_FTN :
1548 : {
1549 137 : SwTextFootnote const *pFootnote = static_cast<SwTextFootnote const *>(pVoid);
1550 137 : if( IsInFootnote() )
1551 : {
1552 : // Am I the first TextFrm of a footnote?
1553 31 : if( !GetPrev() )
1554 : // So we're a TextFrm of the footnote, which has
1555 : // to display the footnote number or the ErgoSum text
1556 27 : InvalidateRange( SwCharRange( 0, 1 ), 1);
1557 :
1558 31 : if( !GetNext() )
1559 : {
1560 : // We're the last Footnote; we need to update the
1561 : // QuoVadis texts now
1562 27 : const SwFootnoteInfo &rFootnoteInfo = GetNode()->GetDoc()->GetFootnoteInfo();
1563 27 : if( !pPara->UpdateQuoVadis( rFootnoteInfo.aQuoVadis ) )
1564 : {
1565 27 : sal_Int32 nPos = pPara->GetParLen();
1566 27 : if( nPos )
1567 6 : --nPos;
1568 27 : InvalidateRange( SwCharRange( nPos, 1 ), 1);
1569 : }
1570 : }
1571 : }
1572 : else
1573 : {
1574 : // We are the TextFrm _with_ the footnote
1575 106 : const sal_Int32 nPos = pFootnote->GetStart();
1576 106 : InvalidateRange( SwCharRange( nPos, 1 ), 1);
1577 : }
1578 137 : break;
1579 : }
1580 : case PREP_BOSS_CHGD :
1581 : {
1582 : // Test
1583 : {
1584 4459 : SetInvalidVert( false );
1585 4459 : bool bOld = IsVertical();
1586 4459 : SetInvalidVert( true );
1587 4459 : if( bOld != IsVertical() )
1588 0 : InvalidateRange( SwCharRange( GetOfst(), COMPLETE_STRING ) );
1589 : }
1590 :
1591 4459 : if( HasFollow() )
1592 : {
1593 24 : sal_Int32 nNxtOfst = GetFollow()->GetOfst();
1594 24 : if( nNxtOfst )
1595 24 : --nNxtOfst;
1596 24 : InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1);
1597 : }
1598 4459 : if( IsInFootnote() )
1599 : {
1600 : sal_Int32 nPos;
1601 25 : if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) )
1602 0 : InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1603 25 : if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) )
1604 0 : InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1605 : }
1606 : // If we have a page number field, we must invalidate those spots
1607 4459 : SwpHints *pHints = GetTextNode()->GetpSwpHints();
1608 4459 : if( pHints )
1609 : {
1610 3163 : const size_t nSize = pHints->Count();
1611 3163 : const sal_Int32 nEnd = GetFollow() ?
1612 3163 : GetFollow()->GetOfst() : COMPLETE_STRING;
1613 11764 : for ( size_t i = 0; i < nSize; ++i )
1614 : {
1615 8615 : const SwTextAttr *pHt = (*pHints)[i];
1616 8615 : const sal_Int32 nStart = pHt->GetStart();
1617 8615 : if( nStart >= GetOfst() )
1618 : {
1619 8615 : if( nStart >= nEnd )
1620 14 : break;
1621 :
1622 : // If we're flowing back and own a Footnote, the Footnote also flows
1623 : // with us. So that it doesn't obstruct us, we send ourselves
1624 : // a ADJUST_FRM.
1625 : // pVoid != 0 means MoveBwd()
1626 8601 : const sal_uInt16 nWhich = pHt->Which();
1627 17204 : if( RES_TXTATR_FIELD == nWhich ||
1628 8589 : (HasFootnote() && pVoid && RES_TXTATR_FTN == nWhich))
1629 17 : InvalidateRange( SwCharRange( nStart, 1 ), 1 );
1630 : }
1631 : }
1632 : }
1633 : // A new boss, a new chance for growing
1634 4459 : if( IsUndersized() )
1635 : {
1636 179 : _InvalidateSize();
1637 179 : InvalidateRange( SwCharRange( GetOfst(), 1 ), 1);
1638 : }
1639 4459 : break;
1640 : }
1641 :
1642 : case PREP_POS_CHGD :
1643 : {
1644 9947 : if ( GetValidPrtAreaFlag() )
1645 : {
1646 9512 : SwTextGridItem const*const pGrid(GetGridItem(FindPageFrm()));
1647 9512 : if ( pGrid && GetTextNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1648 0 : InvalidatePrt();
1649 : }
1650 :
1651 : // If we don't overlap with anybody:
1652 : // did any free-flying frame overlapped _before_ the position change?
1653 9947 : bool bFormat = pPara->HasFly();
1654 9947 : if( !bFormat )
1655 : {
1656 9861 : if( IsInFly() )
1657 : {
1658 293 : SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1659 293 : GetUpper()->Prt().Bottom();
1660 293 : if( nTmpBottom < Frm().Bottom() )
1661 2 : bFormat = true;
1662 : }
1663 9861 : if( !bFormat )
1664 : {
1665 9859 : if ( GetDrawObjs() )
1666 : {
1667 230 : const size_t nCnt = GetDrawObjs()->size();
1668 564 : for ( size_t i = 0; i < nCnt; ++i )
1669 : {
1670 357 : SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
1671 : // #i28701# - consider all
1672 : // to-character anchored objects
1673 357 : if ( pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
1674 : == FLY_AT_CHAR )
1675 : {
1676 23 : bFormat = true;
1677 23 : break;
1678 : }
1679 : }
1680 : }
1681 9859 : if( !bFormat )
1682 : {
1683 : // Are there any free-flying frames on this page?
1684 9836 : SwTextFly aTextFly( this );
1685 9836 : if( aTextFly.IsOn() )
1686 : {
1687 : // Does any free-flying frame overlap?
1688 3039 : bFormat = aTextFly.Relax() || IsUndersized();
1689 9836 : }
1690 : }
1691 : }
1692 : }
1693 :
1694 9947 : if( bFormat )
1695 : {
1696 1971 : if( !IsLocked() )
1697 : {
1698 1971 : if( pPara->GetRepaint().HasArea() )
1699 1971 : SetCompletePaint();
1700 1971 : Init();
1701 1971 : pPara = 0;
1702 1971 : _InvalidateSize();
1703 : }
1704 : }
1705 : else
1706 : {
1707 7976 : if( GetTextNode()->GetSwAttrSet().GetRegister().GetValue() )
1708 0 : bParaPossiblyInvalid = Prepare( PREP_REGISTER, 0, bNotify );
1709 : // The Frames need to be readjusted, which caused by changes
1710 : // in position
1711 7976 : else if( HasFootnote() )
1712 : {
1713 5 : bParaPossiblyInvalid = Prepare( PREP_ADJUST_FRM, 0, bNotify );
1714 5 : _InvalidateSize();
1715 : }
1716 : else
1717 7971 : return bParaPossiblyInvalid; // So that there's no SetPrep()
1718 :
1719 5 : if (bParaPossiblyInvalid)
1720 : {
1721 : // It's possible that pPara was deleted above; retrieve it again
1722 0 : pPara = aAccess.GetPara();
1723 : }
1724 :
1725 : }
1726 1976 : break;
1727 : }
1728 : case PREP_REGISTER:
1729 0 : if( GetTextNode()->GetSwAttrSet().GetRegister().GetValue() )
1730 : {
1731 0 : pPara->SetPrepAdjust();
1732 0 : CalcLineSpace();
1733 :
1734 : // It's possible that pPara was deleted above; retrieve it again
1735 0 : bParaPossiblyInvalid = true;
1736 0 : pPara = aAccess.GetPara();
1737 :
1738 0 : InvalidateSize();
1739 0 : _InvalidatePrt();
1740 : SwFrm* pNxt;
1741 0 : if ( 0 != ( pNxt = GetIndNext() ) )
1742 : {
1743 0 : pNxt->_InvalidatePrt();
1744 0 : if ( pNxt->IsLayoutFrm() )
1745 0 : pNxt->InvalidatePage();
1746 : }
1747 0 : SetCompletePaint();
1748 : }
1749 0 : break;
1750 : case PREP_FTN_GONE :
1751 : {
1752 : // If a Follow is calling us, because a footnote is being deleted, our last
1753 : // line has to be formatted, so that the first line of the Follow can flow up.
1754 : // Which had flowed to the next page to be together with the footnote (this is
1755 : // especially true for areas with columns)
1756 : OSL_ENSURE( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" );
1757 0 : sal_Int32 nPos = GetFollow()->GetOfst();
1758 0 : if( IsFollow() && GetOfst() == nPos ) // If we don't have a mass of text, we call our
1759 0 : FindMaster()->Prepare( PREP_FTN_GONE ); // Master's Prepare
1760 0 : if( nPos )
1761 0 : --nPos; // The char preceding our Follow
1762 0 : InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1763 0 : return bParaPossiblyInvalid;
1764 : }
1765 : case PREP_ERGOSUM:
1766 : case PREP_QUOVADIS:
1767 : {
1768 : sal_Int32 nPos;
1769 79 : if( lcl_ErgoVadis( this, nPos, ePrep ) )
1770 0 : InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1771 : }
1772 79 : break;
1773 : case PREP_FLY_ATTR_CHG:
1774 : {
1775 158 : if( pVoid )
1776 : {
1777 158 : sal_Int32 nWhere = CalcFlyPos( const_cast<SwFrameFormat *>(static_cast<SwFrameFormat const *>(pVoid)) );
1778 : OSL_ENSURE( COMPLETE_STRING != nWhere, "Prepare: Why me?" );
1779 158 : InvalidateRange( SwCharRange( nWhere, 1 ) );
1780 158 : return bParaPossiblyInvalid;
1781 : }
1782 : // else: continue with default case block
1783 : }
1784 : case PREP_CLEAR:
1785 : default:
1786 : {
1787 14106 : if( IsLocked() )
1788 : {
1789 3040 : if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep )
1790 : {
1791 2403 : sal_Int32 nLen = ( GetFollow() ? GetFollow()->GetOfst() :
1792 2403 : COMPLETE_STRING ) - GetOfst();
1793 2394 : InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 );
1794 : }
1795 : }
1796 : else
1797 : {
1798 11066 : if( pPara->GetRepaint().HasArea() )
1799 10327 : SetCompletePaint();
1800 11066 : Init();
1801 11066 : pPara = 0;
1802 11066 : if( GetOfst() && !IsFollow() )
1803 6 : _SetOfst( 0 );
1804 11066 : if ( bNotify )
1805 11059 : InvalidateSize();
1806 : else
1807 7 : _InvalidateSize();
1808 : }
1809 14106 : return bParaPossiblyInvalid; // no SetPrep() happened
1810 : }
1811 : }
1812 17769 : if( pPara )
1813 : {
1814 15798 : pPara->SetPrep();
1815 : }
1816 :
1817 17769 : return bParaPossiblyInvalid;
1818 : }
1819 :
1820 : /**
1821 : * Small Helper class:
1822 : * Prepares a test format.
1823 : * The frame is changed in size and position, its SwParaPortion is moved aside
1824 : * and a new one is created.
1825 : * To achieve this, run formatting with bTestFormat flag set.
1826 : * In the destructor the TextFrm is reset to its original state.
1827 : */
1828 : class SwTestFormat
1829 : {
1830 : SwTextFrm *pFrm;
1831 : SwParaPortion *pOldPara;
1832 : SwRect aOldFrm, aOldPrt;
1833 : public:
1834 : SwTestFormat( SwTextFrm* pTextFrm, const SwFrm* pPrv, SwTwips nMaxHeight );
1835 : ~SwTestFormat();
1836 : };
1837 :
1838 91 : SwTestFormat::SwTestFormat( SwTextFrm* pTextFrm, const SwFrm* pPre, SwTwips nMaxHeight )
1839 91 : : pFrm( pTextFrm )
1840 : {
1841 91 : aOldFrm = pFrm->Frm();
1842 91 : aOldPrt = pFrm->Prt();
1843 :
1844 91 : SWRECTFN( pFrm )
1845 91 : SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)();
1846 :
1847 91 : pFrm->Frm() = pFrm->GetUpper()->Prt();
1848 91 : pFrm->Frm() += pFrm->GetUpper()->Frm().Pos();
1849 :
1850 91 : (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight );
1851 91 : if( pFrm->GetPrev() )
1852 91 : (pFrm->Frm().*fnRect->fnSetPosY)(
1853 91 : (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() -
1854 182 : ( bVert ? nMaxHeight + 1 : 0 ) );
1855 :
1856 91 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1857 91 : const SwBorderAttrs &rAttrs = *aAccess.Get();
1858 91 : (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) );
1859 :
1860 91 : if( pPre )
1861 : {
1862 91 : SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre );
1863 91 : (pFrm->Prt().*fnRect->fnSetPosY)( nUpper );
1864 : }
1865 91 : (pFrm->Prt().*fnRect->fnSetHeight)(
1866 182 : std::max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() -
1867 273 : (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) );
1868 91 : (pFrm->Prt().*fnRect->fnSetWidth)(
1869 91 : (pFrm->Frm().*fnRect->fnGetWidth)() -
1870 182 : ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) );
1871 91 : pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL;
1872 91 : pFrm->SetPara( new SwParaPortion(), false );
1873 :
1874 : OSL_ENSURE( ! pFrm->IsSwapped(), "A frame is swapped before _Format" );
1875 :
1876 91 : if ( pFrm->IsVertical() )
1877 0 : pFrm->SwapWidthAndHeight();
1878 :
1879 182 : SwTextFormatInfo aInf( pFrm, false, true, true );
1880 182 : SwTextFormatter aLine( pFrm, &aInf );
1881 :
1882 91 : pFrm->_Format( aLine, aInf );
1883 :
1884 91 : if ( pFrm->IsVertical() )
1885 0 : pFrm->SwapWidthAndHeight();
1886 :
1887 91 : OSL_ENSURE( ! pFrm->IsSwapped(), "A frame is swapped after _Format" );
1888 91 : }
1889 :
1890 91 : SwTestFormat::~SwTestFormat()
1891 : {
1892 91 : pFrm->Frm() = aOldFrm;
1893 91 : pFrm->Prt() = aOldPrt;
1894 91 : pFrm->SetPara( pOldPara );
1895 91 : }
1896 :
1897 91 : bool SwTextFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, bool &bSplit )
1898 : {
1899 : PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 )
1900 :
1901 91 : if( IsLocked() && GetUpper()->Prt().Width() <= 0 )
1902 0 : return false;
1903 :
1904 91 : SwTestFormat aSave( this, pPrv, rMaxHeight );
1905 :
1906 91 : return SwTextFrm::WouldFit( rMaxHeight, bSplit, true );
1907 : }
1908 :
1909 : /**
1910 : * We should not and don't need to reformat.
1911 : * We assume that we already formatted and that the formatting
1912 : * data is still current.
1913 : *
1914 : * We also assume that the frame width of the Master and Follow
1915 : * are the same. That's why we're not calling FindBreak() for
1916 : * FindOrphans().
1917 : * The required height is coming from nMaxHeight.
1918 : *
1919 : * @returns true if I can split
1920 : */
1921 2986 : bool SwTextFrm::WouldFit( SwTwips &rMaxHeight, bool &bSplit, bool bTst )
1922 : {
1923 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
1924 : "SwTextFrm::WouldFit with swapped frame" );
1925 2986 : SWRECTFN( this );
1926 :
1927 2986 : if( IsLocked() )
1928 0 : return false;
1929 :
1930 : // it can happen that the IdleCollector removed the cached information
1931 2986 : if( !IsEmpty() )
1932 1225 : GetFormatted();
1933 :
1934 : // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph
1935 : // can *not* be applied, if test format is in progress. The test format doesn't
1936 : // adjust the frame and the printing area - see method <SwTextFrm::_Format(..)>,
1937 : // which is called in <SwTextFrm::TestFormat(..)>
1938 2986 : if ( IsEmpty() && !bTst )
1939 : {
1940 1757 : bSplit = false;
1941 1757 : SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height();
1942 1757 : if( rMaxHeight < nHeight )
1943 8 : return false;
1944 : else
1945 : {
1946 1749 : rMaxHeight -= nHeight;
1947 1749 : return true;
1948 : }
1949 : }
1950 :
1951 : // GetPara can still be 0 in edge cases
1952 : // We return true in order to be reformatted on the new Page
1953 : OSL_ENSURE( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" );
1954 1229 : if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) )
1955 0 : return true;
1956 :
1957 : // Because the Orphan flag only exists for a short moment, we also check
1958 : // whether the Framesize is set to very huge by CalcPreps, in order to
1959 : // force a MoveFwd
1960 2458 : if( IsWidow() || ( bVert ?
1961 0 : ( 0 == Frm().Left() ) :
1962 1229 : ( LONG_MAX - 20000 < Frm().Bottom() ) ) )
1963 : {
1964 3 : SetWidow(false);
1965 3 : if ( GetFollow() )
1966 : {
1967 : // If we've ended up here due to a Widow request by our Follow, we check
1968 : // whether there's a Follow with a real height at all.
1969 : // Else (e.g. for newly created SctFrms) we ignore the IsWidow() and
1970 : // still check if we can find enough room
1971 9 : if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) ||
1972 3 : ( bVert && 0 < Frm().Left() ) ) &&
1973 0 : ( GetFollow()->IsVertical() ?
1974 0 : !GetFollow()->Frm().Width() :
1975 0 : !GetFollow()->Frm().Height() ) )
1976 : {
1977 0 : SwTextFrm* pFoll = GetFollow()->GetFollow();
1978 0 : while( pFoll &&
1979 0 : ( pFoll->IsVertical() ?
1980 0 : !pFoll->Frm().Width() :
1981 0 : !pFoll->Frm().Height() ) )
1982 0 : pFoll = pFoll->GetFollow();
1983 0 : if( pFoll )
1984 0 : return false;
1985 : }
1986 : else
1987 3 : return false;
1988 : }
1989 : }
1990 :
1991 1226 : SWAP_IF_NOT_SWAPPED swap( this );
1992 :
1993 2452 : SwTextSizeInfo aInf( this );
1994 2452 : SwTextMargin aLine( this, &aInf );
1995 :
1996 1226 : WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit );
1997 :
1998 1226 : bool bRet = true;
1999 :
2000 1226 : aLine.Bottom();
2001 : // is breaking necessary?
2002 1226 : bSplit = !aFrmBreak.IsInside( aLine );
2003 1226 : if ( bSplit )
2004 100 : bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst );
2005 : else
2006 : {
2007 : // we need the total height including the current line
2008 1126 : aLine.Top();
2009 1313 : do
2010 : {
2011 1313 : rMaxHeight -= aLine.GetLineHeight();
2012 1313 : } while ( aLine.Next() );
2013 : }
2014 :
2015 2452 : return bRet;
2016 : }
2017 :
2018 3474 : sal_uInt16 SwTextFrm::GetParHeight() const
2019 : {
2020 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
2021 : "SwTextFrm::GetParHeight with swapped frame" );
2022 :
2023 3474 : if( !HasPara() )
2024 : { // For non-empty paragraphs this is a special case
2025 : // For UnderSized we can simply just ask 1 Twip more
2026 858 : sal_uInt16 nRet = (sal_uInt16)Prt().SSize().Height();
2027 858 : if( IsUndersized() )
2028 : {
2029 858 : if( IsEmpty() || GetText().isEmpty() )
2030 837 : nRet = (sal_uInt16)EmptyHeight();
2031 : else
2032 21 : ++nRet;
2033 : }
2034 858 : return nRet;
2035 : }
2036 :
2037 : // TODO: Refactor and improve code
2038 2616 : const SwLineLayout* pLineLayout = GetPara();
2039 2616 : sal_uInt16 nHeight = pLineLayout ? pLineLayout->GetRealHeight() : 0;
2040 :
2041 : // Is this paragraph scrolled? Our height until now is at least
2042 : // one line height too low then
2043 2616 : if( GetOfst() && !IsFollow() )
2044 0 : nHeight *= 2;
2045 :
2046 : // OD 2004-03-04 #115793#
2047 5709 : while ( pLineLayout && pLineLayout->GetNext() )
2048 : {
2049 477 : pLineLayout = pLineLayout->GetNext();
2050 477 : nHeight = nHeight + pLineLayout->GetRealHeight();
2051 : }
2052 :
2053 2616 : return nHeight;
2054 : }
2055 :
2056 : /**
2057 : * @returns this _always_ in the formatted state!
2058 : */
2059 89861 : SwTextFrm* SwTextFrm::GetFormatted( bool bForceQuickFormat )
2060 : {
2061 89861 : SWAP_IF_SWAPPED swap( this );
2062 :
2063 : // The IdleCollector could've removed my cached information
2064 : // Calc() calls our format
2065 : // Not for empty paragraphs
2066 89861 : if( !HasPara() && !(IsValid() && IsEmpty()) )
2067 : {
2068 : // Calc() must be called, because frame position can be wrong
2069 222 : const bool bFormat = GetValidSizeFlag();
2070 222 : Calc();
2071 :
2072 : // It could be that Calc() did not trigger Format(), because
2073 : // we've been asked by the IdleCollector to throw away our
2074 : // format information
2075 : // Optimization with FormatQuick()
2076 222 : if( bFormat && !FormatQuick( bForceQuickFormat ) )
2077 0 : Format();
2078 : }
2079 :
2080 89861 : return this;
2081 : }
2082 :
2083 542 : SwTwips SwTextFrm::CalcFitToContent()
2084 : {
2085 : // #i31490#
2086 : // If we are currently locked, we better return with a
2087 : // fairly reasonable value:
2088 542 : if ( IsLocked() )
2089 0 : return Prt().Width();
2090 :
2091 542 : SwParaPortion* pOldPara = GetPara();
2092 542 : SwParaPortion *pDummy = new SwParaPortion();
2093 542 : SetPara( pDummy, false );
2094 542 : const SwPageFrm* pPage = FindPageFrm();
2095 :
2096 542 : const Point aOldFrmPos = Frm().Pos();
2097 542 : const SwTwips nOldFrmWidth = Frm().Width();
2098 542 : const SwTwips nOldPrtWidth = Prt().Width();
2099 542 : const SwTwips nPageWidth = GetUpper()->IsVertical() ?
2100 0 : pPage->Prt().Height() :
2101 542 : pPage->Prt().Width();
2102 :
2103 542 : Frm().Width( nPageWidth );
2104 542 : Prt().Width( nPageWidth );
2105 :
2106 : // #i25422# objects anchored as character in RTL
2107 542 : if ( IsRightToLeft() )
2108 0 : Frm().Pos().X() += nOldFrmWidth - nPageWidth;
2109 :
2110 : // #i31490#
2111 542 : TextFrmLockGuard aLock( this );
2112 :
2113 1084 : SwTextFormatInfo aInf( this, false, true, true );
2114 542 : aInf.SetIgnoreFly( true );
2115 1084 : SwTextFormatter aLine( this, &aInf );
2116 1084 : SwHookOut aHook( aInf );
2117 :
2118 : // #i54031# - assure mininum of MINLAY twips.
2119 : const SwTwips nMax = std::max( (SwTwips)MINLAY,
2120 542 : aLine._CalcFitToContent() + 1 );
2121 :
2122 542 : Frm().Width( nOldFrmWidth );
2123 542 : Prt().Width( nOldPrtWidth );
2124 :
2125 : // #i25422# objects anchored as character in RTL
2126 542 : if ( IsRightToLeft() )
2127 0 : Frm().Pos() = aOldFrmPos;
2128 :
2129 542 : SetPara( pOldPara );
2130 :
2131 1084 : return nMax;
2132 : }
2133 :
2134 : /**
2135 : * Simulate format for a list item paragraph, whose list level attributes
2136 : * are in LABEL_ALIGNMENT mode, in order to determine additional first
2137 : * line offset for the real text formatting due to the value of label
2138 : * adjustment attribute of the list level.
2139 : */
2140 72843 : void SwTextFrm::CalcAdditionalFirstLineOffset()
2141 : {
2142 72843 : if ( IsLocked() )
2143 72843 : return;
2144 :
2145 : // reset additional first line offset
2146 72843 : mnAdditionalFirstLineOffset = 0;
2147 :
2148 72843 : const SwTextNode* pTextNode( GetTextNode() );
2149 76795 : if ( pTextNode && pTextNode->IsNumbered() && pTextNode->IsCountedInList() &&
2150 3952 : pTextNode->GetNumRule() )
2151 : {
2152 3952 : int nListLevel = pTextNode->GetActualListLevel();
2153 :
2154 3952 : if (nListLevel < 0)
2155 0 : nListLevel = 0;
2156 :
2157 3952 : if (nListLevel >= MAXLEVEL)
2158 0 : nListLevel = MAXLEVEL - 1;
2159 :
2160 : const SwNumFormat& rNumFormat =
2161 3952 : pTextNode->GetNumRule()->Get( static_cast<sal_uInt16>(nListLevel) );
2162 3952 : if ( rNumFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2163 : {
2164 : // keep current paragraph portion and apply dummy paragraph portion
2165 3503 : SwParaPortion* pOldPara = GetPara();
2166 3503 : SwParaPortion *pDummy = new SwParaPortion();
2167 3503 : SetPara( pDummy, false );
2168 :
2169 : // lock paragraph
2170 3503 : TextFrmLockGuard aLock( this );
2171 :
2172 : // simulate text formatting
2173 7006 : SwTextFormatInfo aInf( this, false, true, true );
2174 3503 : aInf.SetIgnoreFly( true );
2175 7006 : SwTextFormatter aLine( this, &aInf );
2176 7006 : SwHookOut aHook( aInf );
2177 3503 : aLine._CalcFitToContent();
2178 :
2179 : // determine additional first line offset
2180 3503 : const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion();
2181 3503 : if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFootnoteNumPortion() )
2182 : {
2183 3281 : SwTwips nNumberPortionWidth( pFirstPortion->Width() );
2184 :
2185 3281 : const SwLinePortion* pPortion = pFirstPortion->GetPortion();
2186 12087 : while ( pPortion &&
2187 5525 : pPortion->InNumberGrp() && !pPortion->IsFootnoteNumPortion())
2188 : {
2189 1122 : nNumberPortionWidth += pPortion->Width();
2190 1122 : pPortion = pPortion->GetPortion();
2191 : }
2192 :
2193 6562 : if ( ( IsRightToLeft() &&
2194 6563 : rNumFormat.GetNumAdjust() == SVX_ADJUST_LEFT ) ||
2195 6562 : ( !IsRightToLeft() &&
2196 3281 : rNumFormat.GetNumAdjust() == SVX_ADJUST_RIGHT ) )
2197 : {
2198 1 : mnAdditionalFirstLineOffset = -nNumberPortionWidth;
2199 : }
2200 3280 : else if ( rNumFormat.GetNumAdjust() == SVX_ADJUST_CENTER )
2201 : {
2202 0 : mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2);
2203 : }
2204 : }
2205 :
2206 : // restore paragraph portion
2207 7006 : SetPara( pOldPara );
2208 : }
2209 : }
2210 : }
2211 :
2212 : /**
2213 : * Determine the height of the last line for the calculation of
2214 : * the proportional line spacing
2215 : *
2216 : * Height of last line will be stored in new member
2217 : * mnHeightOfLastLine and can be accessed via method
2218 : * GetHeightOfLastLine()
2219 : *
2220 : * @param _bUseFont force the usage of the former algorithm to
2221 : * determine the height of the last line, which
2222 : * uses the font
2223 : */
2224 74545 : void SwTextFrm::_CalcHeightOfLastLine( const bool _bUseFont )
2225 : {
2226 : // #i71281#
2227 : // invalidate printing area, if height of last line changes
2228 74545 : const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine );
2229 :
2230 : // determine output device
2231 74545 : SwViewShell* pVsh = getRootFrm()->GetCurrShell();
2232 : OSL_ENSURE( pVsh, "<SwTextFrm::_GetHeightOfLastLineForPropLineSpacing()> - no SwViewShell" );
2233 :
2234 : // #i78921# - make code robust, according to provided patch
2235 : // There could be no <SwViewShell> instance in the case of loading a binary
2236 : // StarOffice file format containing an embedded Writer document.
2237 74545 : if ( !pVsh )
2238 : {
2239 0 : return;
2240 : }
2241 74545 : OutputDevice* pOut = pVsh->GetOut();
2242 74545 : const IDocumentSettingAccess* pIDSA = GetTextNode()->getIDocumentSettingAccess();
2243 74589 : if ( !pVsh->GetViewOptions()->getBrowseMode() ||
2244 44 : pVsh->GetViewOptions()->IsPrtFormat() )
2245 : {
2246 74501 : pOut = GetTextNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
2247 : }
2248 : OSL_ENSURE( pOut, "<SwTextFrm::_GetHeightOfLastLineForPropLineSpacing()> - no OutputDevice" );
2249 : // #i78921# - make code robust, according to provided patch
2250 74545 : if ( !pOut )
2251 : {
2252 0 : return;
2253 : }
2254 :
2255 : // determine height of last line
2256 74545 : if ( _bUseFont || pIDSA->get(DocumentSettingId::OLD_LINE_SPACING ) )
2257 : {
2258 : // former determination of last line height for proprotional line
2259 : // spacing - take height of font set at the paragraph
2260 2586 : SwFont aFont( GetAttrSet(), pIDSA );
2261 :
2262 : // we must ensure that the font is restored correctly on the OutputDevice
2263 : // otherwise Last!=Owner could occur
2264 2586 : if ( pLastFont )
2265 : {
2266 2586 : SwFntObj *pOldFont = pLastFont;
2267 2586 : pLastFont = NULL;
2268 2586 : aFont.SetFntChg( true );
2269 2586 : aFont.ChgPhysFnt( pVsh, *pOut );
2270 2586 : mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2271 : //coverity[var_deref_model] - pLastFont is set in SwSubFont::ChgFnt
2272 2586 : pLastFont->Unlock();
2273 2586 : pLastFont = pOldFont;
2274 2586 : pLastFont->SetDevFont( pVsh, *pOut );
2275 : }
2276 : else
2277 : {
2278 0 : vcl::Font aOldFont = pOut->GetFont();
2279 0 : aFont.SetFntChg( true );
2280 0 : aFont.ChgPhysFnt( pVsh, *pOut );
2281 0 : mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2282 : //coverity[var_deref_model] - pLastFont is set in SwSubFont::ChgFnt
2283 0 : pLastFont->Unlock();
2284 0 : pLastFont = NULL;
2285 0 : pOut->SetFont( aOldFont );
2286 2586 : }
2287 : }
2288 : else
2289 : {
2290 : // new determination of last line height - take actually height of last line
2291 : // #i89000#
2292 : // assure same results, if paragraph is undersized
2293 71959 : if ( IsUndersized() )
2294 : {
2295 5052 : mnHeightOfLastLine = 0;
2296 : }
2297 : else
2298 : {
2299 66907 : bool bCalcHeightOfLastLine = true;
2300 66907 : if ( ( !HasPara() && IsEmpty( ) ) || GetText().isEmpty() )
2301 : {
2302 25789 : mnHeightOfLastLine = EmptyHeight();
2303 25789 : bCalcHeightOfLastLine = false;
2304 : }
2305 :
2306 66907 : if ( bCalcHeightOfLastLine )
2307 : {
2308 : OSL_ENSURE( HasPara(),
2309 : "<SwTextFrm::_CalcHeightOfLastLine()> - missing paragraph portions." );
2310 41118 : const SwLineLayout* pLineLayout = GetPara();
2311 147946 : while ( pLineLayout && pLineLayout->GetNext() )
2312 : {
2313 : // iteration to last line
2314 65710 : pLineLayout = pLineLayout->GetNext();
2315 : }
2316 41118 : if ( pLineLayout )
2317 : {
2318 : SwTwips nAscent, nDescent, nDummy1, nDummy2;
2319 : // #i47162# - suppress consideration of
2320 : // fly content portions and the line portion.
2321 : pLineLayout->MaxAscentDescent( nAscent, nDescent,
2322 : nDummy1, nDummy2,
2323 41118 : 0, true );
2324 : // #i71281#
2325 : // Suppress wrong invalidation of printing area, if method is
2326 : // called recursive.
2327 : // Thus, member <mnHeightOfLastLine> is only set directly, if
2328 : // no recursive call is needed.
2329 41118 : const SwTwips nNewHeightOfLastLine = nAscent + nDescent;
2330 : // #i47162# - if last line only contains
2331 : // fly content portions, <mnHeightOfLastLine> is zero.
2332 : // In this case determine height of last line by the font
2333 41118 : if ( nNewHeightOfLastLine == 0 )
2334 : {
2335 2270 : _CalcHeightOfLastLine( true );
2336 : }
2337 : else
2338 : {
2339 38848 : mnHeightOfLastLine = nNewHeightOfLastLine;
2340 : }
2341 : }
2342 : }
2343 : }
2344 : }
2345 : // #i71281#
2346 : // invalidate printing area, if height of last line changes
2347 74545 : if ( mnHeightOfLastLine != mnOldHeightOfLastLine )
2348 : {
2349 34824 : InvalidatePrt();
2350 : }
2351 : }
2352 :
2353 : /**
2354 : * Method returns the value of the inter line spacing for a text frame.
2355 : * Such a value exists for proportional line spacings ("1,5 Lines",
2356 : * "Double", "Proportional" and for leading line spacing ("Leading").
2357 : *
2358 : * @param _bNoPropLineSpacing (default = false) control whether the
2359 : * value of a proportional line spacing is
2360 : * returned or not
2361 : */
2362 96408 : long SwTextFrm::GetLineSpace( const bool _bNoPropLineSpace ) const
2363 : {
2364 96408 : long nRet = 0;
2365 :
2366 96408 : const SwAttrSet* pSet = GetAttrSet();
2367 96408 : const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
2368 :
2369 96408 : switch( rSpace.GetInterLineSpaceRule() )
2370 : {
2371 : case SVX_INTER_LINE_SPACE_PROP:
2372 : {
2373 : // OD 07.01.2004 #i11859#
2374 27973 : if ( _bNoPropLineSpace )
2375 : {
2376 17366 : break;
2377 : }
2378 :
2379 : // OD 2004-03-17 #i11860# - use method GetHeightOfLastLine()
2380 10607 : nRet = GetHeightOfLastLine();
2381 :
2382 10607 : long nTmp = nRet;
2383 10607 : nTmp *= rSpace.GetPropLineSpace();
2384 10607 : nTmp /= 100;
2385 10607 : nTmp -= nRet;
2386 10607 : if ( nTmp > 0 )
2387 10259 : nRet = nTmp;
2388 : else
2389 348 : nRet = 0;
2390 : }
2391 10607 : break;
2392 : case SVX_INTER_LINE_SPACE_FIX:
2393 : {
2394 0 : if ( rSpace.GetInterLineSpace() > 0 )
2395 0 : nRet = rSpace.GetInterLineSpace();
2396 : }
2397 0 : break;
2398 : default:
2399 68435 : break;
2400 : }
2401 96408 : return nRet;
2402 : }
2403 :
2404 1379 : sal_uInt16 SwTextFrm::FirstLineHeight() const
2405 : {
2406 1379 : if ( !HasPara() )
2407 : {
2408 139 : if( IsEmpty() && IsValid() )
2409 138 : return IsVertical() ? (sal_uInt16)Prt().Width() : (sal_uInt16)Prt().Height();
2410 1 : return USHRT_MAX;
2411 : }
2412 1240 : const SwParaPortion *pPara = GetPara();
2413 1240 : if ( !pPara )
2414 0 : return USHRT_MAX;
2415 :
2416 1240 : return pPara->Height();
2417 : }
2418 :
2419 28 : sal_uInt16 SwTextFrm::GetLineCount( sal_Int32 nPos )
2420 : {
2421 28 : sal_uInt16 nRet = 0;
2422 28 : SwTextFrm *pFrm = this;
2423 28 : do
2424 : {
2425 28 : pFrm->GetFormatted();
2426 28 : if( !pFrm->HasPara() )
2427 0 : break;
2428 28 : SwTextSizeInfo aInf( pFrm );
2429 56 : SwTextMargin aLine( pFrm, &aInf );
2430 28 : if( COMPLETE_STRING == nPos )
2431 28 : aLine.Bottom();
2432 : else
2433 0 : aLine.CharToLine( nPos );
2434 28 : nRet = nRet + aLine.GetLineNr();
2435 56 : pFrm = pFrm->GetFollow();
2436 28 : } while ( pFrm && pFrm->GetOfst() <= nPos );
2437 28 : return nRet;
2438 : }
2439 :
2440 72663 : void SwTextFrm::ChgThisLines()
2441 : {
2442 : // not necessary to format here (GerFormatted etc.), because we have to come from there!
2443 72663 : sal_uLong nNew = 0;
2444 72663 : const SwLineNumberInfo &rInf = GetNode()->GetDoc()->GetLineNumberInfo();
2445 72663 : if ( !GetText().isEmpty() && HasPara() )
2446 : {
2447 43562 : SwTextSizeInfo aInf( this );
2448 87124 : SwTextMargin aLine( this, &aInf );
2449 43562 : if ( rInf.IsCountBlankLines() )
2450 : {
2451 43562 : aLine.Bottom();
2452 43562 : nNew = (sal_uLong)aLine.GetLineNr();
2453 : }
2454 : else
2455 : {
2456 0 : do
2457 : {
2458 0 : if( aLine.GetCurr()->HasContent() )
2459 0 : ++nNew;
2460 0 : } while ( aLine.NextLine() );
2461 43562 : }
2462 : }
2463 29101 : else if ( rInf.IsCountBlankLines() )
2464 29101 : nNew = 1;
2465 :
2466 72663 : if ( nNew != nThisLines )
2467 : {
2468 34923 : if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
2469 : {
2470 24936 : nAllLines -= nThisLines;
2471 24936 : nThisLines = nNew;
2472 24936 : nAllLines += nThisLines;
2473 24936 : SwFrm *pNxt = GetNextContentFrm();
2474 50190 : while( pNxt && pNxt->IsInTab() )
2475 : {
2476 318 : if( 0 != (pNxt = pNxt->FindTabFrm()) )
2477 318 : pNxt = pNxt->FindNextCnt();
2478 : }
2479 24936 : if( pNxt )
2480 19736 : pNxt->InvalidateLineNum();
2481 :
2482 : // Extend repaint to the bottom.
2483 24936 : if ( HasPara() )
2484 : {
2485 18457 : SwRepaint& rRepaint = GetPara()->GetRepaint();
2486 18457 : rRepaint.Bottom( std::max( rRepaint.Bottom(),
2487 36914 : Frm().Top()+Prt().Bottom()));
2488 : }
2489 : }
2490 : else // Paragraphs which are not counted should not manipulate the AllLines.
2491 9987 : nThisLines = nNew;
2492 : }
2493 72663 : }
2494 :
2495 36445 : void SwTextFrm::RecalcAllLines()
2496 : {
2497 36445 : ValidateLineNum();
2498 :
2499 36445 : const SwAttrSet *pAttrSet = GetAttrSet();
2500 :
2501 36445 : if ( !IsInTab() )
2502 : {
2503 25941 : const sal_uLong nOld = GetAllLines();
2504 25941 : const SwFormatLineNumber &rLineNum = pAttrSet->GetLineNumber();
2505 : sal_uLong nNewNum;
2506 25941 : const bool bRestart = GetTextNode()->GetDoc()->GetLineNumberInfo().IsRestartEachPage();
2507 :
2508 25941 : if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() )
2509 3 : nNewNum = rLineNum.GetStartValue() - 1;
2510 : // If it is a follow or not has not be considered if it is a restart at each page; the
2511 : // restart should also take affekt at follows.
2512 25938 : else if ( bRestart && FindPageFrm()->FindFirstBodyContent() == this )
2513 : {
2514 0 : nNewNum = 0;
2515 : }
2516 : else
2517 : {
2518 25938 : SwContentFrm *pPrv = GetPrevContentFrm();
2519 130957 : while ( pPrv &&
2520 68682 : (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) )
2521 19319 : pPrv = pPrv->GetPrevContentFrm();
2522 :
2523 : // #i78254# Restart line numbering at page change
2524 : // First body content may be in table!
2525 25938 : if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() )
2526 0 : pPrv = 0;
2527 :
2528 25938 : nNewNum = pPrv ? static_cast<SwTextFrm*>(pPrv)->GetAllLines() : 0;
2529 : }
2530 25941 : if ( rLineNum.IsCount() )
2531 25498 : nNewNum += GetThisLines();
2532 :
2533 25941 : if ( nOld != nNewNum )
2534 : {
2535 20631 : nAllLines = nNewNum;
2536 20631 : SwContentFrm *pNxt = GetNextContentFrm();
2537 304178 : while ( pNxt &&
2538 195040 : (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) )
2539 81421 : pNxt = pNxt->GetNextContentFrm();
2540 20631 : if ( pNxt )
2541 : {
2542 18653 : if ( pNxt->GetUpper() != GetUpper() )
2543 7496 : pNxt->InvalidateLineNum();
2544 : else
2545 11157 : pNxt->_InvalidateLineNum();
2546 : }
2547 : }
2548 : }
2549 36445 : }
2550 :
2551 1062 : void SwTextFrm::VisitPortions( SwPortionHandler& rPH ) const
2552 : {
2553 1062 : const SwParaPortion* pPara = IsValid() ? GetPara() : NULL;
2554 :
2555 1062 : if (pPara)
2556 : {
2557 619 : if ( IsFollow() )
2558 1 : rPH.Skip( GetOfst() );
2559 :
2560 619 : const SwLineLayout* pLine = pPara;
2561 1889 : while ( pLine )
2562 : {
2563 651 : const SwLinePortion* pPor = pLine->GetFirstPortion();
2564 2168 : while ( pPor )
2565 : {
2566 866 : pPor->HandlePortion( rPH );
2567 866 : pPor = pPor->GetPortion();
2568 : }
2569 :
2570 651 : rPH.LineBreak(pLine->Width());
2571 651 : pLine = pLine->GetNext();
2572 : }
2573 : }
2574 :
2575 1062 : rPH.Finish();
2576 1062 : }
2577 :
2578 95954 : const SwScriptInfo* SwTextFrm::GetScriptInfo() const
2579 : {
2580 95954 : const SwParaPortion* pPara = GetPara();
2581 95954 : return pPara ? &pPara->GetScriptInfo() : 0;
2582 : }
2583 :
2584 : /**
2585 : * Helper function for SwTextFrm::CalcBasePosForFly()
2586 : */
2587 109250 : static SwTwips lcl_CalcFlyBasePos( const SwTextFrm& rFrm, SwRect aFlyRect,
2588 : SwTextFly& rTextFly )
2589 : {
2590 109250 : SWRECTFN( (&rFrm) )
2591 109250 : SwTwips nRet = rFrm.IsRightToLeft() ?
2592 138 : (rFrm.Frm().*fnRect->fnGetRight)() :
2593 109388 : (rFrm.Frm().*fnRect->fnGetLeft)();
2594 :
2595 172 : do
2596 : {
2597 109391 : SwRect aRect = rTextFly.GetFrm( aFlyRect );
2598 109391 : if ( 0 != (aRect.*fnRect->fnGetWidth)() )
2599 : {
2600 450 : if ( rFrm.IsRightToLeft() )
2601 : {
2602 0 : if ( (aRect.*fnRect->fnGetRight)() -
2603 0 : (aFlyRect.*fnRect->fnGetRight)() >= 0 )
2604 : {
2605 : (aFlyRect.*fnRect->fnSetRight)(
2606 0 : (aRect.*fnRect->fnGetLeft)() );
2607 0 : nRet = (aRect.*fnRect->fnGetLeft)();
2608 : }
2609 : else
2610 109219 : break;
2611 : }
2612 : else
2613 : {
2614 900 : if ( (aFlyRect.*fnRect->fnGetLeft)() -
2615 450 : (aRect.*fnRect->fnGetLeft)() >= 0 )
2616 : {
2617 : (aFlyRect.*fnRect->fnSetLeft)(
2618 172 : (aRect.*fnRect->fnGetRight)() + 1 );
2619 172 : nRet = (aRect.*fnRect->fnGetRight)();
2620 : }
2621 : else
2622 278 : break;
2623 : }
2624 : }
2625 : else
2626 108941 : break;
2627 : }
2628 172 : while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 );
2629 :
2630 109250 : return nRet;
2631 : }
2632 :
2633 72275 : void SwTextFrm::CalcBaseOfstForFly()
2634 : {
2635 : OSL_ENSURE( !IsVertical() || !IsSwapped(),
2636 : "SwTextFrm::CalcBasePosForFly with swapped frame!" );
2637 :
2638 72275 : const SwNode* pNode = GetTextNode();
2639 72275 : if ( !pNode->getIDocumentSettingAccess()->get(DocumentSettingId::ADD_FLY_OFFSETS) )
2640 89925 : return;
2641 :
2642 54625 : SWRECTFN( this )
2643 :
2644 54625 : SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() );
2645 :
2646 : // Get first 'real' line and adjust position and height of line rectangle
2647 : // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour,
2648 : // if no 'real' line exists (empty paragraph with and without a dummy portion)
2649 : {
2650 54625 : SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)();
2651 54625 : const SwLineLayout* pLay = GetPara();
2652 54625 : SwTwips nLineHeight = 200;
2653 109346 : while( pLay && pLay->IsDummy() && pLay->GetNext() )
2654 : {
2655 96 : nTop += pLay->Height();
2656 96 : pLay = pLay->GetNext();
2657 : }
2658 54625 : if ( pLay )
2659 : {
2660 42015 : nLineHeight = pLay->Height();
2661 : }
2662 54625 : (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight );
2663 : }
2664 :
2665 54625 : SwTextFly aTextFly( this );
2666 54625 : aTextFly.SetIgnoreCurrentFrame( true );
2667 54625 : aTextFly.SetIgnoreContour( true );
2668 : // #118809# - ignore objects in page header|footer for
2669 : // text frames not in page header|footer
2670 54625 : aTextFly.SetIgnoreObjsInHeaderFooter( true );
2671 54625 : SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTextFly );
2672 54625 : aTextFly.SetIgnoreCurrentFrame( false );
2673 54625 : SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTextFly );
2674 :
2675 : // make values relative to frame start position
2676 54625 : SwTwips nLeft = IsRightToLeft() ?
2677 69 : (Frm().*fnRect->fnGetRight)() :
2678 54694 : (Frm().*fnRect->fnGetLeft)();
2679 :
2680 54625 : mnFlyAnchorOfst = nRet1 - nLeft;
2681 54625 : mnFlyAnchorOfstNoWrap = nRet2 - nLeft;
2682 : }
2683 :
2684 : /**
2685 : * Repaint all text frames of the given text node
2686 : */
2687 0 : void SwTextFrm::repaintTextFrames( const SwTextNode& rNode )
2688 : {
2689 0 : SwIterator<SwTextFrm,SwTextNode> aIter( rNode );
2690 0 : for( const SwTextFrm *pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
2691 : {
2692 0 : SwRect aRec( pFrm->PaintArea() );
2693 0 : const SwRootFrm *pRootFrm = pFrm->getRootFrm();
2694 0 : SwViewShell *pCurShell = pRootFrm ? pRootFrm->GetCurrShell() : NULL;
2695 0 : if( pCurShell )
2696 0 : pCurShell->InvalidateWindows( aRec );
2697 0 : }
2698 177 : }
2699 :
2700 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|