LibreOffice Module sw (master)  1
txtfly.cxx
Go to the documentation of this file.
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 <vcl/outdev.hxx>
21 
22 #include <pagefrm.hxx>
23 #include <rootfrm.hxx>
24 #include <pam.hxx>
25 #include <swfont.hxx>
26 #include <swregion.hxx>
27 #include <dflyobj.hxx>
28 #include <drawfont.hxx>
29 #include <flyfrm.hxx>
30 #include <flyfrms.hxx>
31 #include <fmtornt.hxx>
32 #include <frmatr.hxx>
33 #include <frmtool.hxx>
34 #include <ndtxt.hxx>
35 #include <txtfly.hxx>
36 #include "txtpaint.hxx"
37 #include <notxtfrm.hxx>
38 #include <fmtcnct.hxx>
39 #include <svx/obj3d.hxx>
40 #include <editeng/txtrange.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/ulspitem.hxx>
43 #include <fmtsrnd.hxx>
44 #include <fmtanchr.hxx>
45 #include <frmfmt.hxx>
46 #include <pagedesc.hxx>
47 #include <sortedobjs.hxx>
50 #include <svx/svdoedge.hxx>
51 
52 #ifdef DBG_UTIL
53 #include <viewsh.hxx>
54 #include <doc.hxx>
55 #endif
56 
57 using namespace ::com::sun::star;
58 
59 namespace
60 {
61  // #i68520#
62  struct AnchoredObjOrder
63  {
64  bool const mbR2L;
65  SwRectFn mfnRect;
66 
67  AnchoredObjOrder( const bool bR2L,
68  SwRectFn fnRect )
69  : mbR2L( bR2L ),
70  mfnRect( fnRect )
71  {}
72 
73  bool operator()( const SwAnchoredObject* pListedAnchoredObj,
74  const SwAnchoredObject* pNewAnchoredObj )
75  {
76  const SwRect& aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
77  const SwRect& aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
78  if ( ( mbR2L &&
79  ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
80  (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
81  ( !mbR2L &&
82  ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
83  (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
84  {
85  SwTwips nTopDiff =
86  (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
87  (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
88  if ( nTopDiff == 0 &&
89  ( ( mbR2L &&
90  ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
91  (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
92  ( !mbR2L &&
93  ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
94  (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
95  {
96  return true;
97  }
98  else if ( nTopDiff > 0 )
99  {
100  return true;
101  }
102  }
103  else if ( ( mbR2L &&
104  ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
105  (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
106  ( !mbR2L &&
107  ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
108  (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
109  {
110  return true;
111  }
112 
113  return false;
114  }
115  };
116 }
117 
119  nPntCnt( 0 )
120 {
121 }
122 
124 {
125 }
126 
127 void SwContourCache::ClrObject( sal_uInt16 nPos )
128 {
129  nPntCnt -= mvItems[ nPos ].mxTextRanger->GetPointCount();
130  mvItems.erase(mvItems.begin() + nPos);
131 }
132 
133 void ClrContourCache( const SdrObject *pObj )
134 {
135  if( pContourCache && pObj )
136  for( sal_uInt16 i = 0; i < pContourCache->GetCount(); ++i )
137  if( pObj == pContourCache->GetObject( i ) )
138  {
140  break;
141  }
142 }
143 
145 {
146  if( pContourCache )
147  {
148  pContourCache->mvItems.clear();
149  pContourCache->nPntCnt = 0;
150  }
151 }
152 
153 // #i68520#
155  const SwRect &rLine,
156  const SwTextFrame* pFrame,
157  const long nXPos,
158  const bool bRight )
159 {
160  SwRect aRet;
161  const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
162  bool bHandleContour(pFormat->GetSurround().IsContour());
163 
164  if(!bHandleContour)
165  {
166  // RotateFlyFrame3: Object has no set contour, but for rotated
167  // FlyFrames we can create a 'default' contour to make text
168  // flow around the free, non-covered
169  const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(pAnchoredObj));
170 
171  if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->supportsAutoContour())
172  {
173  bHandleContour = true;
174  }
175  }
176 
177  if( bHandleContour &&
178  ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) == nullptr ||
179  ( static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower() &&
180  static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower()->IsNoTextFrame() ) ) )
181  {
182  aRet = pAnchoredObj->GetObjRectWithSpaces();
183  if( aRet.IsOver( rLine ) )
184  {
185  if( !pContourCache )
187 
188  aRet = pContourCache->ContourRect(
189  pFormat, pAnchoredObj->GetDrawObj(), pFrame, rLine, nXPos, bRight );
190  }
191  else
192  aRet.Width( 0 );
193  }
194  else
195  {
196  aRet = pAnchoredObj->GetObjRectWithSpaces();
197  }
198 
199  return aRet;
200 }
201 
203  const SdrObject* pObj, const SwTextFrame* pFrame, const SwRect &rLine,
204  const long nXPos, const bool bRight )
205 {
206  SwRect aRet;
207  sal_uInt16 nPos = 0; // Search in the Cache
208  while( nPos < GetCount() && pObj != mvItems[ nPos ].mpSdrObj )
209  ++nPos;
210  if( GetCount() == nPos ) // Not found
211  {
212  if( GetCount() == POLY_CNT )
213  {
214  nPntCnt -= mvItems.back().mxTextRanger->GetPointCount();
215  mvItems.pop_back();
216  }
217  ::basegfx::B2DPolyPolygon aPolyPolygon;
218  std::unique_ptr<::basegfx::B2DPolyPolygon> pPolyPolygon;
219 
220  if ( auto pVirtFlyDrawObj = dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) )
221  {
222  // GetContour() causes the graphic to be loaded, which may cause
223  // the graphic to change its size, call ClrObject()
224  tools::PolyPolygon aPoly;
225  if( !pVirtFlyDrawObj->GetFlyFrame()->GetContour( aPoly ) )
226  aPoly = tools::PolyPolygon( static_cast<const SwVirtFlyDrawObj*>(pObj)->
227  GetFlyFrame()->getFrameArea().SVRect() );
228  aPolyPolygon.clear();
229  aPolyPolygon.append(aPoly.getB2DPolyPolygon());
230  }
231  else
232  {
233  if( dynamic_cast< const E3dObject *>( pObj ) == nullptr )
234  {
235  aPolyPolygon = pObj->TakeXorPoly();
236  }
237 
238  ::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour());
239  pPolyPolygon.reset(new ::basegfx::B2DPolyPolygon(aContourPoly));
240  }
241  const SvxLRSpaceItem &rLRSpace = pFormat->GetLRSpace();
242  const SvxULSpaceItem &rULSpace = pFormat->GetULSpace();
243  CacheItem item {
244  pObj, // due to #37347 the Object must be entered only after GetContour()
245  std::make_unique<TextRanger>( aPolyPolygon, pPolyPolygon.get(), 20,
246  static_cast<sal_uInt16>(rLRSpace.GetLeft()), static_cast<sal_uInt16>(rLRSpace.GetRight()),
247  pFormat->GetSurround().IsOutside(), false, pFrame->IsVertical() )
248  };
249  mvItems.insert(mvItems.begin(), std::move(item));
250  mvItems[0].mxTextRanger->SetUpper( rULSpace.GetUpper() );
251  mvItems[0].mxTextRanger->SetLower( rULSpace.GetLower() );
252 
253  pPolyPolygon.reset();
254 
255  nPntCnt += mvItems[0].mxTextRanger->GetPointCount();
256  while( nPntCnt > POLY_MAX && mvItems.size() > POLY_MIN )
257  {
258  nPntCnt -= mvItems.back().mxTextRanger->GetPointCount();
259  mvItems.pop_back();
260  }
261  }
262  else if( nPos )
263  {
264  CacheItem item = std::move(mvItems[nPos]);
265  mvItems.erase(mvItems.begin() + nPos);
266  mvItems.insert(mvItems.begin(), std::move(item));
267  }
268  SwRectFnSet aRectFnSet(pFrame);
269  long nTmpTop = aRectFnSet.GetTop(rLine);
270  // fnGetBottom is top + height
271  long nTmpBottom = aRectFnSet.GetBottom(rLine);
272 
273  Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );
274 
275  LongDqPtr pTmp = mvItems[0].mxTextRanger->GetTextRanges( aRange );
276 
277  const size_t nCount = pTmp->size();
278  if( 0 != nCount )
279  {
280  size_t nIdx = 0;
281  while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
282  ++nIdx;
283  bool bOdd = nIdx % 2;
284  bool bSet = true;
285  if( bOdd )
286  --nIdx; // within interval
287  else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
288  {
289  if( nIdx )
290  nIdx -= 2; // an interval to the left
291  else
292  bSet = false; // before the first interval
293  }
294 
295  if( bSet && nIdx < nCount )
296  {
297  aRectFnSet.SetTopAndHeight( aRet, aRectFnSet.GetTop(rLine),
298  aRectFnSet.GetHeight(rLine) );
299  aRectFnSet.SetLeft( aRet, (*pTmp)[ nIdx ] );
300  aRectFnSet.SetRight( aRet, (*pTmp)[ nIdx + 1 ] + 1 );
301  }
302  }
303  return aRet;
304 }
305 
307  : pPage(nullptr)
308  , mpCurrAnchoredObj(nullptr)
309  , m_pCurrFrame(nullptr)
310  , m_pMaster(nullptr)
311  , nMinBottom(0)
312  , nNextTop(0)
313  , m_nCurrFrameNodeIndex(0)
314  , bOn(false)
315  , bTopRule(false)
316  , mbIgnoreCurrentFrame(false)
317  , mbIgnoreContour(false)
318  , mbIgnoreObjsInHeaderFooter(false)
319 
320 {
321 }
322 
324 {
325  CtorInitTextFly( pFrame );
326 }
327 
328 SwTextFly::SwTextFly( const SwTextFly& rTextFly )
329 {
330  pPage = rTextFly.pPage;
332  m_pCurrFrame = rTextFly.m_pCurrFrame;
333  m_pMaster = rTextFly.m_pMaster;
334  if( rTextFly.mpAnchoredObjList )
335  {
336  mpAnchoredObjList.reset( new SwAnchoredObjList( *(rTextFly.mpAnchoredObjList) ) );
337  }
338 
339  bOn = rTextFly.bOn;
340  bTopRule = rTextFly.bTopRule;
341  nMinBottom = rTextFly.nMinBottom;
342  nNextTop = rTextFly.nNextTop;
345  mbIgnoreContour = rTextFly.mbIgnoreContour;
347 }
348 
350 {
351 }
352 
354 {
355  mbIgnoreCurrentFrame = false;
356  mbIgnoreContour = false;
358  pPage = pFrame->FindPageFrame();
359  const SwFlyFrame* pTmp = pFrame->FindFlyFrame();
360  // #i68520#
361  mpCurrAnchoredObj = pTmp;
362  m_pCurrFrame = pFrame;
363  m_pMaster = m_pCurrFrame->IsFollow() ? nullptr : m_pCurrFrame;
364  // If we're not overlapped by a frame or if a FlyCollection does not exist
365  // at all, we switch off forever.
366  // It could be, however, that a line is added while formatting, that
367  // extends into a frame.
368  // That's why we do not optimize for: bOn = pSortedFlys && IsAnyFrame();
369  bOn = pPage->GetSortedObjs() != nullptr;
370  bTopRule = true;
371  nMinBottom = 0;
372  nNextTop = 0;
373  m_nCurrFrameNodeIndex = ULONG_MAX;
374 }
375 
376 SwRect SwTextFly::GetFrame_( const SwRect &rRect ) const
377 {
378  SwRect aRet;
379  if( ForEach( rRect, &aRet, true ) )
380  {
381  SwRectFnSet aRectFnSet(m_pCurrFrame);
382  aRectFnSet.SetTop( aRet, aRectFnSet.GetTop(rRect) );
383 
384  // Do not always adapt the bottom
385  const SwTwips nRetBottom = aRectFnSet.GetBottom(aRet);
386  const SwTwips nRectBottom = aRectFnSet.GetBottom(rRect);
387  if ( aRectFnSet.YDiff( nRetBottom, nRectBottom ) > 0 ||
388  aRectFnSet.GetHeight(aRet) < 0 )
389  aRectFnSet.SetBottom( aRet, nRectBottom );
390  }
391  return aRet;
392 }
393 
395 {
396  SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
397 
398  OSL_ENSURE( bOn, "IsAnyFrame: Why?" );
401 
402  return ForEach( aRect, nullptr, false );
403 }
404 
405 bool SwTextFly::IsAnyObj( const SwRect &rRect ) const
406 {
407  OSL_ENSURE( bOn, "SwTextFly::IsAnyObj: Who's knocking?" );
408 
409  SwRect aRect( rRect );
410  if ( aRect.IsEmpty() )
411  {
414  }
415 
416  const SwSortedObjs *pSorted = pPage->GetSortedObjs();
417  if( pSorted ) // bOn actually makes sure that we have objects on the side,
418  // but who knows who deleted something in the meantime?
419  {
420  for ( size_t i = 0; i < pSorted->size(); ++i )
421  {
422  const SwAnchoredObject* pObj = (*pSorted)[i];
423 
424  const SwRect aBound( pObj->GetObjRectWithSpaces() );
425 
426  // Optimization
427  if( pObj->GetObjRect().Left() > aRect.Right() )
428  continue;
429 
430  // #i68520#
431  if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
432  return true;
433  }
434  }
435  return false;
436 }
437 
439 {
441  while (m_pMaster && m_pMaster->IsFollow())
443  return m_pMaster;
444 }
445 
447 {
448  SwSaveClip aClipSave( rInf.GetpOut() );
449  SwRect aRect( rInf.GetPos(), rInf.GetSize() );
450  if( rInf.GetSpace() )
451  {
452  TextFrameIndex const nTmpLen = TextFrameIndex(COMPLETE_STRING) == rInf.GetLen()
453  ? TextFrameIndex(rInf.GetText().getLength())
454  : rInf.GetLen();
455  if( rInf.GetSpace() > 0 )
456  {
457  sal_Int32 nSpaceCnt = 0;
458  const TextFrameIndex nEndPos = rInf.GetIdx() + nTmpLen;
459  for (TextFrameIndex nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos)
460  {
461  if (CH_BLANK == rInf.GetText()[sal_Int32(nPos)])
462  ++nSpaceCnt;
463  }
464  if( nSpaceCnt )
465  aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
466  }
467  else
468  aRect.Width( aRect.Width() - sal_Int32(nTmpLen) * rInf.GetSpace() );
469  }
470 
471  if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
472  {
473  SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
474  aRect.Intersection( aClipRect );
475  }
476 
477  SwRegionRects aRegion( aRect );
478 
479  bool bOpaque = false;
480  // #i68520#
481  const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
483  : SAL_MAX_UINT32;
484  OSL_ENSURE( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
485 
486  // #i68520#
487  const SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
488  if (nCount > 0)
489  {
491  for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
492  {
493  // #i68520#
494  const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
495  if( dynamic_cast<const SwFlyFrame*>(pTmpAnchoredObj) &&
496  mpCurrAnchoredObj != pTmpAnchoredObj )
497  {
498  // #i68520#
499  const SwFlyFrame& rFly = dynamic_cast<const SwFlyFrame&>(*pTmpAnchoredObj);
500  if( aRegion.GetOrigin().IsOver( rFly.getFrameArea() ) )
501  {
502  const SwFrameFormat *pFormat = rFly.GetFormat();
503  const SwFormatSurround &rSur = pFormat->GetSurround();
504  const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
505  // Only the ones who are opaque and more to the top
506  if( ! rFly.IsBackgroundTransparent() &&
507  css::text::WrapTextMode_THROUGH == rSur.GetSurround() &&
508  ( !rSur.IsAnchorOnly() ||
509  // #i68520#
510  GetMaster() == rFly.GetAnchorFrame() ||
511  ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
512  (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId())
513  )
514  ) &&
515  // #i68520#
516  pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
517  nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
518  )
519  {
520  // Except for the content is transparent
521  const SwNoTextFrame *pNoText =
522  rFly.Lower() && rFly.Lower()->IsNoTextFrame()
523  ? static_cast<const SwNoTextFrame*>(rFly.Lower())
524  : nullptr;
525  if ( !pNoText ||
526  (!pNoText->IsTransparent() && !rSur.IsContour()) )
527  {
528  bOpaque = true;
529  aRegion -= rFly.getFrameArea();
530  }
531  }
532  }
533  }
534  }
535  }
536 
537  Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
538  const Point aOldPos(rInf.GetPos());
539  rInf.SetPos( aPos );
540 
541  if( !bOpaque )
542  {
543  if( rInf.GetKern() )
544  rInf.GetFont()->DrawStretchText_( rInf );
545  else
546  rInf.GetFont()->DrawText_( rInf );
547  rInf.SetPos(aOldPos);
548  return;
549  }
550  else if( !aRegion.empty() )
551  {
552  // What a huge effort ...
553  SwSaveClip aClipVout( rInf.GetpOut() );
554  for( size_t i = 0; i < aRegion.size(); ++i )
555  {
556  SwRect &rRect = aRegion[i];
557  if( rRect != aRegion.GetOrigin() )
558  aClipVout.ChgClip( rRect );
559  if( rInf.GetKern() )
560  rInf.GetFont()->DrawStretchText_( rInf );
561  else
562  rInf.GetFont()->DrawText_( rInf );
563  }
564  }
565  rInf.SetPos(aOldPos);
566 }
567 
568 void SwTextFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect )
569 {
570  SwRegionRects aRegion( rRect );
571  OSL_ENSURE( !bTopRule, "DrawFlyRect: Wrong TopRule" );
572  // #i68520#
573  const SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
574  if (nCount > 0)
575  {
577  for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
578  {
579  // #i68520#
580  const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
581  if (mpCurrAnchoredObj == pAnchoredObjTmp)
582  continue;
583 
584  // #i68520#
585  const SwFlyFrame* pFly = dynamic_cast<const SwFlyFrame*>(pAnchoredObjTmp);
586  if (pFly)
587  {
588  // #i68520#
589  const SwFormatSurround& rSur = pAnchoredObjTmp->GetFrameFormat().GetSurround();
590 
591  // OD 24.01.2003 #106593# - correct clipping of fly frame area.
592  // Consider that fly frame background/shadow can be transparent
593  // and <SwAlignRect(..)> fly frame area
594  // #i47804# - consider transparent graphics
595  // and OLE objects.
596  bool bClipFlyArea =
597  ( ( css::text::WrapTextMode_THROUGH == rSur.GetSurround() )
598  // #i68520#
599  ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
600  : !rSur.IsContour() ) &&
601  !pFly->IsBackgroundTransparent() &&
602  ( !pFly->Lower() ||
603  !pFly->Lower()->IsNoTextFrame() ||
604  !static_cast<const SwNoTextFrame*>(pFly->Lower())->IsTransparent() );
605  if ( bClipFlyArea )
606  {
607  // #i68520#
608  SwRect aFly( pAnchoredObjTmp->GetObjRect() );
609  // OD 24.01.2003 #106593#
610  ::SwAlignRect( aFly, pPage->getRootFrame()->GetCurrShell(), pOut );
611  if( aFly.Width() > 0 && aFly.Height() > 0 )
612  aRegion -= aFly;
613  }
614  }
615  }
616  }
617 
618  for( size_t i = 0; i < aRegion.size(); ++i )
619  {
620  pOut->DrawRect( aRegion[i].SVRect() );
621  }
622 }
623 
628 bool SwTextFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
629  const bool bInFootnote,
630  const bool bInFooterOrHeader )
631 {
632  // #i68520#
633  // <mpCurrAnchoredObj> is set, if <m_pCurrFrame> is inside a fly frame
634  if( _pAnchoredObj != mpCurrAnchoredObj )
635  {
636  // #i26945#
637  const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
638  // #102344# Ignore connectors which have one or more connections
639  if (const SdrEdgeObj* pEdgeObj = dynamic_cast<const SdrEdgeObj*>(pNew))
640  {
641  if (pEdgeObj->GetConnectedNode(true) || pEdgeObj->GetConnectedNode(false))
642  {
643  return false;
644  }
645  }
646 
647  if( ( bInFootnote || bInFooterOrHeader ) && bTopRule )
648  {
649  // #i26945#
650  const SwFrameFormat& rFrameFormat = _pAnchoredObj->GetFrameFormat();
651  const SwFormatAnchor& rNewA = rFrameFormat.GetAnchor();
652  if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
653  {
654  if ( bInFootnote )
655  return false;
656 
657  if ( bInFooterOrHeader )
658  {
659  const SwFormatVertOrient& aVert( rFrameFormat.GetVertOrient() );
660  bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
661  aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
662  if( bVertPrt )
663  return false;
664  }
665  }
666  }
667 
668  // #i68520#
669  // bEvade: consider pNew, if we are not inside a fly
670  // consider pNew, if pNew is lower of <mpCurrAnchoredObj>
671  bool bEvade = !mpCurrAnchoredObj ||
672  Is_Lower_Of( dynamic_cast<const SwFlyFrame*>(mpCurrAnchoredObj), pNew);
673 
674  if ( !bEvade )
675  {
676  // We are currently inside a fly frame and pNew is not
677  // inside this fly frame. We can do some more checks if
678  // we have to consider pNew.
679 
680  // If bTopRule is not set, we ignore the frame types.
681  // We directly check the z-order
682  if ( !bTopRule )
683  bEvade = true;
684  else
685  {
686  // Within chained Flys we only avoid Lower
687  // #i68520#
689  if ( !rChain.GetPrev() && !rChain.GetNext() )
690  {
691  // #i26945#
692  const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat().GetAnchor();
693  // #i68520#
695 
696  // If <mpCurrAnchoredObj> is anchored as character, its content
697  // does not wrap around pNew
698  if (RndStdIds::FLY_AS_CHAR == rCurrA.GetAnchorId())
699  return false;
700 
701  // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
702  // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
703  // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
704  // some more checks
705  if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
706  {
707  if (RndStdIds::FLY_AT_PAGE == rCurrA.GetAnchorId())
708  {
709  bEvade = true;
710  }
711  else
712  return false;
713  }
714  else if (RndStdIds::FLY_AT_PAGE == rCurrA.GetAnchorId())
715  return false; // Page anchored ones only avoid page anchored ones
716  else if (RndStdIds::FLY_AT_FLY == rNewA.GetAnchorId())
717  bEvade = true; // Non-page anchored ones avoid frame anchored ones
718  else if( RndStdIds::FLY_AT_FLY == rCurrA.GetAnchorId() )
719  return false; // Frame anchored ones do not avoid paragraph anchored ones
720  // #i57062#
721  // In order to avoid loop situation, it's decided to adjust
722  // the wrapping behaviour of content of at-paragraph/at-character
723  // anchored objects to one in the page header/footer and
724  // the document body --> content of at-paragraph/at-character
725  // anchored objects doesn't wrap around each other.
726  else
727  return false;
728  }
729  }
730 
731  // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
732  // #i68520#
733  bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
734  if( bEvade )
735  {
736  // #i68520#
737  const SwRect& aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
738  if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
739  bEvade = false;
740  }
741  }
742 
743  if ( bEvade )
744  {
745  // #i26945#
746  const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat().GetAnchor();
747  OSL_ENSURE( RndStdIds::FLY_AS_CHAR != rNewA.GetAnchorId(),
748  "Don't call GetTop with a FlyInContentFrame" );
749  if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
750  return true; // We always avoid page anchored ones
751 
752  // If Flys anchored at paragraph are caught in a FlyCnt, then
753  // their influence ends at the borders of the FlyCnt!
754  // If we are currently formatting the text of the FlyCnt, then
755  // it has to get out of the way of the Frame anchored at paragraph!
756  // m_pCurrFrame is the anchor of pNew?
757  // #i26945#
758  const SwFrame* pTmp = _pAnchoredObj->GetAnchorFrame();
759  if (pTmp == m_pCurrFrame)
760  return true;
761  if( pTmp->IsTextFrame() && ( pTmp->IsInFly() || pTmp->IsInFootnote() ) )
762  {
763  // #i26945#
764  Point aPos = _pAnchoredObj->GetObjRect().Pos();
765  pTmp = GetVirtualUpper( pTmp, aPos );
766  }
767  // #i26945#
768  // If <pTmp> is a text frame inside a table, take the upper
769  // of the anchor frame, which contains the anchor position.
770  else if ( pTmp->IsTextFrame() && pTmp->IsInTab() )
771  {
772  pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
773  ->GetAnchorFrameContainingAnchPos()->GetUpper();
774  }
775  // #i28701# - consider all objects in same context,
776  // if wrapping style is considered on object positioning.
777  // Thus, text will wrap around negative positioned objects.
778  // #i3317# - remove condition on checking,
779  // if wrappings style is considered on object positioning.
780  // Thus, text is wrapping around negative positioned objects.
781  // #i35640# - no consideration of negative
782  // positioned objects, if wrapping style isn't considered on
783  // object position and former text wrapping is applied.
784  // This condition is typically for documents imported from the
785  // OpenOffice.org file format.
790  {
791  return true;
792  }
793 
794  const SwFrame* pHeader = nullptr;
795  if (m_pCurrFrame->GetNext() != pTmp &&
797  // #i13832#, #i24135# wrap around objects in page header
799  nullptr != ( pHeader = pTmp->FindFooterOrHeader() ) &&
801  {
802  if( pHeader || RndStdIds::FLY_AT_FLY == rNewA.GetAnchorId() )
803  return true;
804 
805  // Compare indices:
806  // The Index of the other is retrieved from the anchor attr.
807  sal_uLong nTmpIndex = rNewA.GetContentAnchor()->nNode.GetIndex();
808  // Now check whether the current paragraph is before the anchor
809  // of the displaced object in the text, then we don't have to
810  // get out of its way.
811  // If possible determine Index via SwFormatAnchor because
812  // otherwise it's quite expensive.
813  if (ULONG_MAX == m_nCurrFrameNodeIndex)
815 
816  if (FrameContainsNode(*m_pCurrFrame, nTmpIndex) || nTmpIndex < m_nCurrFrameNodeIndex)
817  return true;
818  }
819  }
820  }
821  return false;
822 }
823 
824 // #i68520#
826 {
827  OSL_ENSURE( m_pCurrFrame, "InitFlyList: No Frame, no FlyList" );
828  // #i68520#
829  OSL_ENSURE( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
830 
831  SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
832 
833  const SwSortedObjs *pSorted = pPage->GetSortedObjs();
834  const size_t nCount = pSorted ? pSorted->size() : 0;
835  // --> #108724# Page header/footer content doesn't have to wrap around
836  // floating screen objects
837  const bool bFooterHeader = nullptr != m_pCurrFrame->FindFooterOrHeader();
839  // #i40155# - check, if frame is marked not to wrap
840  const bool bWrapAllowed = ( pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ||
841  (!m_pCurrFrame->IsInFootnote() && !bFooterHeader));
842 
843  bOn = false;
844 
845  if( nCount && bWrapAllowed )
846  {
847  // #i68520#
849 
850  // #i28701# - consider complete frame area for new
851  // text wrapping
852  SwRect aRect;
854  {
855  aRect = m_pCurrFrame->getFramePrintArea();
856  aRect += m_pCurrFrame->getFrameArea().Pos();
857  }
858  else
859  {
860  aRect = m_pCurrFrame->getFrameArea();
861  }
862  // Make ourselves a little smaller than we are,
863  // so that 1-Twip-overlappings are ignored (#49532)
864  SwRectFnSet aRectFnSet(m_pCurrFrame);
865  const long nRight = aRectFnSet.GetRight(aRect) - 1;
866  const long nLeft = aRectFnSet.GetLeft(aRect) + 1;
867  const bool bR2L = m_pCurrFrame->IsRightToLeft();
868 
870 
871  for( size_t i = 0; i < nCount; ++i )
872  {
873  // #i68520#
874  // do not consider hidden objects
875  // check, if object has to be considered for text wrap
876  // #118809# - If requested, do not consider
877  // objects in page header|footer for text frames not in page
878  // header|footer. This is requested for the calculation of
879  // the base offset for objects <SwTextFrame::CalcBaseOfstForFly()>
880  // #i20505# Do not consider oversized objects
881  SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
882  assert(pAnchoredObj);
883  if ( !pAnchoredObj ||
884  !rIDDMA.IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
885  !pAnchoredObj->ConsiderForTextWrap() ||
886  ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
887  pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() ) )
888  {
889  continue;
890  }
891 
892  const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
893  if ( nRight < aRectFnSet.GetLeft(aBound) ||
894  aRectFnSet.YDiff( aRectFnSet.GetTop(aRect),
895  aRectFnSet.GetBottom(aBound) ) > 0 ||
896  nLeft > aRectFnSet.GetRight(aBound) ||
897  aRectFnSet.GetHeight(aBound) >
898  2 * aRectFnSet.GetHeight(pPage->getFrameArea()) )
899  {
900  continue;
901  }
902 
903  // #i26945# - pass <pAnchoredObj> to method
904  // <GetTop(..)> instead of only the <SdrObject> instance of the
905  // anchored object
906  if (GetTop(pAnchoredObj, m_pCurrFrame->IsInFootnote(), bFooterHeader))
907  {
908  // OD 11.03.2003 #107862# - adjust insert position:
909  // overlapping objects should be sorted from left to right and
910  // inside left to right sorting from top to bottom.
911  // If objects on the same position are found, they are sorted
912  // on its width.
913  // #i68520#
914  {
915  SwAnchoredObjList::iterator aInsPosIter =
916  std::lower_bound( mpAnchoredObjList->begin(),
917  mpAnchoredObjList->end(),
918  pAnchoredObj,
919  AnchoredObjOrder( bR2L, aRectFnSet.FnRect() ) );
920 
921  mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
922  }
923 
924  const SwFormatSurround &rFlyFormat = pAnchoredObj->GetFrameFormat().GetSurround();
925  // #i68520#
926  if ( rFlyFormat.IsAnchorOnly() &&
927  pAnchoredObj->GetAnchorFrame() == GetMaster() )
928  {
929  const SwFormatVertOrient &rTmpFormat =
930  pAnchoredObj->GetFrameFormat().GetVertOrient();
931  if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
932  nMinBottom = ( aRectFnSet.IsVert() && nMinBottom ) ?
933  std::min( nMinBottom, aBound.Left() ) :
934  std::max( nMinBottom, aRectFnSet.GetBottom(aBound) );
935  }
936 
937  bOn = true;
938  }
939  }
940  if( nMinBottom )
941  {
942  SwTwips nMax = aRectFnSet.GetPrtBottom(*m_pCurrFrame->GetUpper());
943  if( aRectFnSet.YDiff( nMinBottom, nMax ) > 0 )
944  nMinBottom = nMax;
945  }
946  }
947  else
948  {
949  // #i68520#
951  }
952 
953  // #i68520#
954  return mpAnchoredObjList.get();
955 }
956 
958 {
959  SwTwips nRet = 0;
960  const SwContentFrame *pLclMaster = GetMaster();
961  OSL_ENSURE(pLclMaster, "SwTextFly without master");
962  const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : nullptr;
963  const size_t nCount = pDrawObj ? pDrawObj->size() : 0;
964  if( nCount )
965  {
966  SwTwips nEndOfFrame = m_pCurrFrame->getFrameArea().Bottom();
967  for( size_t i = 0; i < nCount; ++i )
968  {
969  SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
970  const SwFormatSurround &rFlyFormat = pAnchoredObj->GetFrameFormat().GetSurround();
971  if( rFlyFormat.IsAnchorOnly() )
972  {
973  const SwFormatVertOrient &rTmpFormat =
974  pAnchoredObj->GetFrameFormat().GetVertOrient();
975  if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
976  {
977  const SwRect& aBound( pAnchoredObj->GetObjRectWithSpaces() );
978  if( aBound.Top() < nEndOfFrame )
979  nRet = std::max( nRet, aBound.Bottom() );
980  }
981  }
982  }
983  SwTwips nMax = m_pCurrFrame->GetUpper()->getFrameArea().Top() +
985  if( nRet > nMax )
986  nRet = nMax;
987  }
988  return nRet;
989 }
990 
991 bool SwTextFly::ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const
992 {
993  SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
994 
995  // Optimization
996  SwRectFnSet aRectFnSet(m_pCurrFrame);
997 
998  // tdf#127235 stop if the area is larger than the page
999  if( aRectFnSet.GetHeight(pPage->getFrameArea()) < aRectFnSet.GetHeight(rRect))
1000  {
1001  // get the doc model description
1002  const SwPageDesc* pPageDesc = pPage->GetPageDesc();
1003 
1004  // if there is no next page style or it is the same as the current
1005  // => stop trying to place the frame (it would end in an infinite loop)
1006  if( pPageDesc &&
1007  ( !pPageDesc->GetFollow() || pPageDesc->GetFollow() == pPageDesc) )
1008  {
1009  return false;
1010  }
1011  }
1012 
1013  bool bRet = false;
1014  // #i68520#
1015  const SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1016  if (nCount > 0)
1017  {
1018  for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1019  {
1020  // #i68520#
1021  const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1022 
1023  SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1024 
1025  if( aRectFnSet.GetLeft(aRect) > aRectFnSet.GetRight(rRect) )
1026  break;
1027 
1028  // #i68520#
1029  if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
1030  {
1031  // #i68520#
1032  const SwFormat* pFormat( &(pAnchoredObj->GetFrameFormat()) );
1033  const SwFormatSurround &rSur = pFormat->GetSurround();
1034  if( bAvoid )
1035  {
1036  // If the text flows below, it has no influence on
1037  // formatting. In LineIter::DrawText() it is "just"
1038  // necessary to cleverly set the ClippingRegions
1039  const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1040  if( ( css::text::WrapTextMode_THROUGH == rSur.GetSurround() &&
1041  ( !rSur.IsAnchorOnly() ||
1042  // #i68520#
1043  GetMaster() == pAnchoredObj->GetAnchorFrame() ||
1044  ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
1045  (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
1046  || aRect.Top() == FAR_AWAY )
1047  continue;
1048  }
1049 
1050  // #i58642#
1051  // Compare <GetMaster()> instead of <m_pCurrFrame> with the
1052  // anchor frame of the anchored object, because a follow frame
1053  // has to ignore the anchored objects of its master frame.
1054  // Note: Anchored objects are always registered at the master
1055  // frame, exception are as-character anchored objects,
1056  // but these aren't handled here.
1057  // #i68520#
1058  if ( mbIgnoreCurrentFrame &&
1059  GetMaster() == pAnchoredObj->GetAnchorFrame() )
1060  continue;
1061 
1062  if( pRect )
1063  {
1064  // #i68520#
1065  SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
1066  if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
1067  continue;
1068  if( !bRet || (
1069  (!m_pCurrFrame->IsRightToLeft() &&
1070  ( aRectFnSet.GetLeft(aFly) <
1071  aRectFnSet.GetLeft(*pRect) ) ) ||
1073  ( aRectFnSet.GetRight(aFly) >
1074  aRectFnSet.GetRight(*pRect) ) ) ) )
1075  *pRect = aFly;
1076  if( rSur.IsContour() )
1077  {
1078  bRet = true;
1079  continue;
1080  }
1081  }
1082  bRet = true;
1083  break;
1084  }
1085  }
1086  }
1087 
1088  return bRet;
1089 }
1090 
1091 // #i68520#
1092 SwAnchoredObjList::size_type SwTextFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
1093 {
1094  SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
1095  SwAnchoredObjList::size_type nRet = 0;
1096  while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
1097  ++nRet;
1098  return nRet;
1099 }
1100 
1101 // #i68520#
1103  SwAnchoredObjList::size_type nFlyPos,
1104  const SwRect &rLine ) const
1105 {
1106  // Usually the right margin is the right margin of the Printarea
1107  OSL_ENSURE( !m_pCurrFrame->IsVertical() || !m_pCurrFrame->IsSwapped(),
1108  "SwTextFly::CalcRightMargin with swapped frame" );
1109  SwRectFnSet aRectFnSet(m_pCurrFrame);
1110  // #118796# - correct determination of right of printing area
1111  SwTwips nRight = aRectFnSet.GetPrtRight(*m_pCurrFrame);
1112  SwTwips nFlyRight = aRectFnSet.GetRight(rFly);
1113  SwRect aLine( rLine );
1114  aRectFnSet.SetRight( aLine, nRight );
1115  aRectFnSet.SetLeft( aLine, aRectFnSet.GetLeft(rFly) );
1116 
1117  // It is possible that there is another object that is _above_ us
1118  // and protrudes into the same line.
1119  // Flys with run-through are invisible for those below, i.e., they
1120  // are ignored for computing the margins of other Flys.
1121  // 3301: pNext->getFrameArea().IsOver( rLine ) is necessary
1122  // #i68520#
1123  css::text::WrapTextMode eSurroundForTextWrap;
1124 
1125  bool bStop = false;
1126  // #i68520#
1127  SwAnchoredObjList::size_type nPos = 0;
1128 
1129  // #i68520#
1130  while( nPos < mpAnchoredObjList->size() && !bStop )
1131  {
1132  if( nPos == nFlyPos )
1133  {
1134  ++nPos;
1135  continue;
1136  }
1137  // #i68520#
1138  const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
1139  if ( pNext == mpCurrAnchoredObj )
1140  continue;
1141  eSurroundForTextWrap = GetSurroundForTextWrap( pNext );
1142  if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap )
1143  continue;
1144 
1146  ( pNext, aLine, m_pCurrFrame, nFlyRight, true ) );
1147  SwTwips nTmpRight = aRectFnSet.GetRight(aTmp);
1148 
1149  // optimization:
1150  // Record in nNextTop at which Y-position frame related changes are
1151  // likely. This is so that, despite only looking at frames in the
1152  // current line height, for frames without wrap the line height is
1153  // incremented so that with a single line the lower border of the frame
1154  // (or possibly the upper border of another frame) is reached.
1155  // Especially in HTML documents there are often (dummy) paragraphs in
1156  // 2 pt font, and they used to only evade big frames after huge numbers
1157  // of empty lines.
1158  const long nTmpTop = aRectFnSet.GetTop(aTmp);
1159  if( aRectFnSet.YDiff( nTmpTop, aRectFnSet.GetTop(aLine) ) > 0 )
1160  {
1161  if( aRectFnSet.YDiff( nNextTop, nTmpTop ) > 0 )
1162  SetNextTop( nTmpTop ); // upper border of next frame
1163  }
1164  else if (!aRectFnSet.GetWidth(aTmp)) // typical for Objects with contour wrap
1165  { // For Objects with contour wrap that start before the current
1166  // line, and end below it, but do not actually overlap it, the
1167  // optimization has to be disabled, because the circumstances
1168  // can change in the next line.
1169  if( ! aRectFnSet.GetHeight(aTmp) ||
1170  aRectFnSet.YDiff( aRectFnSet.GetBottom(aTmp),
1171  aRectFnSet.GetTop(aLine) ) > 0 )
1172  SetNextTop( 0 );
1173  }
1174  if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
1175  {
1176  nFlyRight = nTmpRight;
1177  if( css::text::WrapTextMode_RIGHT == eSurroundForTextWrap ||
1178  css::text::WrapTextMode_PARALLEL == eSurroundForTextWrap )
1179  {
1180  // overrule the FlyFrame
1181  if( nRight > nFlyRight )
1182  nRight = nFlyRight;
1183  bStop = true;
1184  }
1185  }
1186  }
1187  aRectFnSet.SetRight( rFly, nRight );
1188 }
1189 
1190 // #i68520#
1192  SwAnchoredObjList::size_type nFlyPos,
1193  const SwRect &rLine ) const
1194 {
1195  OSL_ENSURE( !m_pCurrFrame->IsVertical() || !m_pCurrFrame->IsSwapped(),
1196  "SwTextFly::CalcLeftMargin with swapped frame" );
1197  SwRectFnSet aRectFnSet(m_pCurrFrame);
1198  // #118796# - correct determination of left of printing area
1199  SwTwips nLeft = aRectFnSet.GetPrtLeft(*m_pCurrFrame);
1200  const SwTwips nFlyLeft = aRectFnSet.GetLeft(rFly);
1201 
1202  if( nLeft > nFlyLeft )
1203  nLeft = rFly.Left();
1204 
1205  SwRect aLine( rLine );
1206  aRectFnSet.SetLeft( aLine, nLeft );
1207 
1208  // It is possible that there is another object that is _above_ us
1209  // and protrudes into the same line.
1210  // Flys with run-through are invisible for those below, i.e., they
1211  // are ignored for computing the margins of other Flys.
1212  // 3301: pNext->getFrameArea().IsOver( rLine ) is necessary
1213 
1214  // #i68520#
1215  SwAnchoredObjList::size_type nMyPos = nFlyPos;
1216  while( ++nFlyPos < mpAnchoredObjList->size() )
1217  {
1218  // #i68520#
1219  const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1220  const SwRect& aTmp( pNext->GetObjRectWithSpaces() );
1221  if( aRectFnSet.GetLeft(aTmp) >= nFlyLeft )
1222  break;
1223  }
1224 
1225  while( nFlyPos )
1226  {
1227  if( --nFlyPos == nMyPos )
1228  continue;
1229  // #i68520#
1230  const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1231  if( pNext == mpCurrAnchoredObj )
1232  continue;
1233  css::text::WrapTextMode eSurroundForTextWrap = GetSurroundForTextWrap( pNext );
1234  if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap )
1235  continue;
1236 
1238  (pNext, aLine, m_pCurrFrame, nFlyLeft, false) );
1239 
1240  if( aRectFnSet.GetLeft(aTmp) < nFlyLeft && aTmp.IsOver( aLine ) )
1241  {
1242  // #118796# - no '+1', because <..fnGetRight>
1243  // returns the correct value.
1244  SwTwips nTmpRight = aRectFnSet.GetRight(aTmp);
1245  if ( nLeft <= nTmpRight )
1246  nLeft = nTmpRight;
1247 
1248  break;
1249  }
1250  }
1251  aRectFnSet.SetLeft( rFly, nLeft );
1252 }
1253 
1254 // #i68520#
1256  const SwRect &rLine ) const
1257 {
1258  SwRectFnSet aRectFnSet(m_pCurrFrame);
1259 
1260  const long nXPos = m_pCurrFrame->IsRightToLeft() ?
1261  rLine.Right() :
1262  aRectFnSet.GetLeft(rLine);
1263 
1264  SwRect aFly = mbIgnoreContour ?
1265  pAnchoredObj->GetObjRectWithSpaces() :
1266  SwContourCache::CalcBoundRect(pAnchoredObj, rLine, m_pCurrFrame,
1267  nXPos, !m_pCurrFrame->IsRightToLeft());
1268 
1269  if( !aFly.Width() )
1270  return aFly;
1271 
1272  // so the line may grow up to the lower edge of the frame
1273  SetNextTop( aRectFnSet.GetBottom(aFly) );
1274  SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );
1275 
1276  // LEFT and RIGHT, we grow the rectangle.
1277  // We have some problems, when several frames are to be seen.
1278  // At the moment, only the easier case is assumed:
1279  // + LEFT means that the text must flow on the left of the frame,
1280  // that is the frame expands to the right edge of the print area
1281  // or to the next frame.
1282  // + RIGHT is the opposite.
1283  // Otherwise the set distance between text and frame is always
1284  // added up.
1285  switch( GetSurroundForTextWrap( pAnchoredObj ) )
1286  {
1287  case css::text::WrapTextMode_LEFT :
1288  {
1289  CalcRightMargin( aFly, nFlyPos, rLine );
1290  break;
1291  }
1292  case css::text::WrapTextMode_RIGHT :
1293  {
1294  CalcLeftMargin( aFly, nFlyPos, rLine );
1295  break;
1296  }
1297  case css::text::WrapTextMode_NONE :
1298  {
1299  CalcRightMargin( aFly, nFlyPos, rLine );
1300  CalcLeftMargin( aFly, nFlyPos, rLine );
1301  break;
1302  }
1303  default:
1304  break;
1305  }
1306  return aFly;
1307 }
1308 
1309 // #i68520#
1310 
1311 // Wrap only on sides with at least 2cm space for the text
1312 #define TEXT_MIN 1134
1313 
1314 // MS Word wraps on sides with even less space (value guessed).
1315 #define TEXT_MIN_SMALL 300
1316 
1317 // Wrap on both sides up to a frame width of 1.5cm
1318 #define FRAME_MAX 850
1319 
1320 css::text::WrapTextMode SwTextFly::GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
1321 {
1322  const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
1323  const SwFormatSurround &rFlyFormat = pFormat->GetSurround();
1324  css::text::WrapTextMode eSurroundForTextWrap = rFlyFormat.GetSurround();
1325 
1326  if( rFlyFormat.IsAnchorOnly() && pAnchoredObj->GetAnchorFrame() != GetMaster() )
1327  {
1328  const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1329  if ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
1330  (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()))
1331  {
1332  return css::text::WrapTextMode_NONE;
1333  }
1334  }
1335 
1336  // in cause of run-through and nowrap ignore smartly
1337  if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap ||
1338  css::text::WrapTextMode_NONE == eSurroundForTextWrap )
1339  return eSurroundForTextWrap;
1340 
1341  // left is left and right is right
1342  if (m_pCurrFrame->IsRightToLeft())
1343  {
1344  if ( css::text::WrapTextMode_LEFT == eSurroundForTextWrap )
1345  eSurroundForTextWrap = css::text::WrapTextMode_RIGHT;
1346  else if ( css::text::WrapTextMode_RIGHT == eSurroundForTextWrap )
1347  eSurroundForTextWrap = css::text::WrapTextMode_LEFT;
1348  }
1349 
1350  // "ideal page wrap":
1351  if ( css::text::WrapTextMode_DYNAMIC == eSurroundForTextWrap )
1352  {
1353  SwRectFnSet aRectFnSet(m_pCurrFrame);
1354  const long nCurrLeft = aRectFnSet.GetPrtLeft(*m_pCurrFrame);
1355  const long nCurrRight = aRectFnSet.GetPrtRight(*m_pCurrFrame);
1356  const SwRect& aRect( pAnchoredObj->GetObjRectWithSpaces() );
1357  long nFlyLeft = aRectFnSet.GetLeft(aRect);
1358  long nFlyRight = aRectFnSet.GetRight(aRect);
1359 
1360  if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
1361  eSurroundForTextWrap = css::text::WrapTextMode_PARALLEL;
1362  else
1363  {
1364  long nLeft = nFlyLeft - nCurrLeft;
1365  long nRight = nCurrRight - nFlyRight;
1366  if( nFlyRight - nFlyLeft > FRAME_MAX )
1367  {
1368  if( nLeft < nRight )
1369  nLeft = 0;
1370  else
1371  nRight = 0;
1372  }
1373  const int textMin = GetMaster()->GetDoc()
1376 
1377  // In case there is no space on either side, then css::text::WrapTextMode_PARALLEL
1378  // gives the same result when doing the initial layout or a layout
1379  // update after editing, so prefer that over css::text::WrapTextMode_NONE.
1380  if (nLeft == 0 && nRight == 0)
1381  return css::text::WrapTextMode_PARALLEL;
1382 
1383  if( nLeft < textMin )
1384  nLeft = 0;
1385  if( nRight < textMin )
1386  nRight = 0;
1387  if( nLeft )
1388  eSurroundForTextWrap = nRight ? css::text::WrapTextMode_PARALLEL : css::text::WrapTextMode_LEFT;
1389  else
1390  eSurroundForTextWrap = nRight ? css::text::WrapTextMode_RIGHT: css::text::WrapTextMode_NONE;
1391  }
1392  }
1393 
1394  return eSurroundForTextWrap;
1395 }
1396 
1397 bool SwTextFly::IsAnyFrame( const SwRect &rLine ) const
1398 {
1399 
1400  SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
1401 
1402  OSL_ENSURE( bOn, "IsAnyFrame: Why?" );
1403 
1404  return ForEach( rLine, nullptr, false );
1405 }
1406 
1407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwAnchoredObjList * GetAnchoredObjList() const
Definition: txtfly.hxx:301
long GetLeft() const
SwFrame * FindFooterOrHeader()
Definition: findfrm.cxx:547
vcl::Region GetClipRegion() const
bool IsContour() const
Definition: fmtsrnd.hxx:53
Base class of the Writer layout elements.
Definition: frame.hxx:295
virtual basegfx::B2DPolyPolygon TakeXorPoly() const
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
virtual SwRect GetObjRect() const =0
void SetTopAndHeight(SwRect &rRect, long nTop, long nHeight) const
Definition: frame.hxx:1404
sal_uLong GetIndex() const
Definition: node.hxx:282
long GetSpace() const
Definition: drawfont.hxx:325
bool IsFollow() const
Definition: flowfrm.hxx:166
virtual const SwFlyFrameFormat * GetFormat() const override
Definition: fly.cxx:2800
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:543
const SwRect & GetOrigin() const
Definition: swregion.hxx:47
bool IsInDocBody() const
Definition: frame.hxx:919
bool IsInFly() const
Definition: frame.hxx:937
long nNextTop
Definition: txtfly.hxx:128
const SwFrame * FindContext(const SwFrame *pFrame, SwFrameType nAdditionalContextTyp)
provides the area of a frame in that no Fly from another area can overlap
Definition: frmtool.cxx:3393
sal_uInt16 GetLower() const
vcl::RenderContext * GetpOut() const
Definition: drawfont.hxx:185
bool IsAnyFrame() const
Same as IsAnyFrame(const SwRect&), but uses the current frame print area.
Definition: txtfly.cxx:394
SwFont * GetFont() const
Definition: drawfont.hxx:250
bool IsSwapped() const
Definition: txtfrm.hxx:528
bool IsAnyObj(const SwRect &rRect) const
true when a frame or DrawObj must be taken in account.
Definition: txtfly.cxx:405
bool mbIgnoreObjsInHeaderFooter
boolean, indicating if objects in page header|footer are considered for text frames not in page heade...
Definition: txtfly.hxx:139
bool bTopRule
Definition: txtfly.hxx:132
SwRect GetFrame_(const SwRect &rPortion) const
This method will be called during the LineIter formatting.
Definition: txtfly.cxx:376
const SwTextFrame * GetMaster_()
Definition: txtfly.cxx:438
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
SwNodeIndex nNode
Definition: pam.hxx:37
void ClrObject(sal_uInt16 nPos)
Definition: txtfly.cxx:127
bool IsInFootnote() const
Definition: frame.hxx:925
SwRectFn FnRect() const
Definition: frame.hxx:1345
#define TEXT_MIN_SMALL
Definition: txtfly.cxx:1315
sal_uIntPtr sal_uLong
const SwRect & getFramePrintArea() const
Definition: frame.hxx:176
void DrawFlyRect(OutputDevice *pOut, const SwRect &rRect)
Two subtleties needs to be mentioned:
Definition: txtfly.cxx:568
The purpose of this class is to be the universal interface between formatting/text output and the pos...
Definition: txtfly.hxx:119
SwAnchoredObjList * InitAnchoredObjList()
Definition: txtfly.cxx:825
#define POLY_CNT
Definition: txtfly.hxx:46
bool bOn
Definition: txtfly.hxx:131
void SetPos(const Point &rNew)
Definition: drawfont.hxx:397
long GetBottom(const SwRect &rRect) const
Definition: frame.hxx:1354
long SwTwips
Definition: swtypes.hxx:49
#define TEXT_MIN
Definition: txtfly.cxx:1312
sal_uInt16 GetAscent() const
Definition: drawfont.hxx:299
SwContourCache * pContourCache
Contour-cache global variable, initialized/destroyed in txtinit.cxx and needed in txtfly...
Definition: txtinit.cxx:31
bool IsVert() const
Definition: frame.hxx:1343
void Pos(const Point &rNew)
Definition: swrect.hxx:167
bool IsBackgroundTransparent() const
SwFlyFrame::IsBackgroundTransparent.
Definition: paintfrm.cxx:3741
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
tools::Rectangle GetBoundRect() const
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:55
SwTwips CalcMinBottom() const
Definition: txtfly.cxx:957
const SwAnchoredObject * mpCurrAnchoredObj
Definition: txtfly.hxx:122
bool mbIgnoreCurrentFrame
Definition: txtfly.hxx:133
void DrawText_(SwDrawTextInfo &rInf)
Definition: swfont.hxx:317
std::deque< long > * LongDqPtr
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
Definition: doc.cxx:154
const SwTextFrame * m_pMaster
Definition: txtfly.hxx:124
SwRectGet fnGetRight
Definition: frame.hxx:1270
long YDiff(long n1, long n2) const
Definition: frame.hxx:1399
#define SAL_MAX_UINT32
const SwPageFrame * pPage
Definition: txtfly.hxx:121
wrapper class for the positioning of Writer fly frames and drawing objects
virtual bool IsVisibleLayerId(SdrLayerID _nLayerId) const =0
method to determine, if a layer ID belongs to the visible ones.
long GetPrtBottom(const SwFrame &rFrame) const
Definition: frame.hxx:1386
void Top(const long nTop)
Definition: swrect.hxx:202
void SwAlignRect(SwRect &rRect, const SwViewShell *pSh, const vcl::RenderContext *pRenderContext)
Function is also used outside this file.
Definition: paintfrm.cxx:1123
const SwRect & getFrameArea() const
Definition: frame.hxx:175
bool IsInTab() const
Definition: frame.hxx:931
void CalcLeftMargin(SwRect &rFly, SwAnchoredObjList::size_type nPos, const SwRect &rLine) const
The left margin is the left margin of the current PrintArea or it is determined by the last FlyFrame...
Definition: txtfly.cxx:1191
SwRect & Intersection(const SwRect &rRect)
Definition: swrect.cxx:54
int nCount
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
#define POLY_MIN
Definition: txtfly.hxx:47
bool IsFrameInSameContext(const SwFrame *pInnerFrame, const SwFrame *pFrame)
Definition: frmtool.cxx:3407
bool IsTextFrame() const
Definition: frame.hxx:1210
bool IsAnchorOnly() const
Definition: fmtsrnd.hxx:52
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
long GetKern() const
Definition: drawfont.hxx:320
SwRect ContourRect(const SwFormat *pFormat, const SdrObject *pObj, const SwTextFrame *pFrame, const SwRect &rLine, const long nXPos, const bool bRight)
Definition: txtfly.cxx:202
sal_uLong m_nCurrFrameNodeIndex
Stores the upper edge of the "next" frame.
Definition: txtfly.hxx:129
SwFlyFrame * FindFlyFrame()
Definition: frame.hxx:1087
long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1355
long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1356
void Right(const long nRight)
Definition: swrect.hxx:198
void DrawTextOpaque(SwDrawTextInfo &rInf)
This method is called by DrawText().
Definition: txtfly.cxx:446
const IDocumentDrawModelAccess & getIDocumentDrawModelAccess() const
Provides access to the document draw model interface.
Definition: viewsh.cxx:2584
#define POLY_MAX
Definition: txtfly.hxx:48
bool IsEmpty() const
Definition: swrect.hxx:294
void ClrContourCache(const SdrObject *pObj)
Definition: txtfly.cxx:133
void SetBottom(SwRect &rRect, long nNew) const
Definition: frame.hxx:1363
void DrawRect(const tools::Rectangle &rRect)
const OUString & GetText() const
Definition: drawfont.hxx:216
Base class for various Writer styles.
Definition: format.hxx:43
std::vector< CacheItem > mvItems
Definition: txtfly.hxx:60
bool ConsiderForTextWrap() const
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
SwTextNode * GetTextNodeFirst()
Definition: txtfrm.hxx:447
bool FrameContainsNode(SwContentFrame const &rFrame, sal_uLong nNodeIndex)
Definition: txtfrm.cxx:284
Style of a layout element.
Definition: frmfmt.hxx:57
void SetTop(SwRect &rRect, long nNew) const
Definition: frame.hxx:1362
const SdrObject * GetDrawObj() const
const SwSortedObjs * GetSortedObjs() const
Definition: pagefrm.hxx:118
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
bool IsClipRegion() const
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
size_t size() const
Definition: sortedobjs.cxx:42
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
SwPageFrame * FindPageFrame()
Definition: frame.hxx:658
const SwFrame * Lower() const
Definition: layfrm.hxx:101
int i
long nPntCnt
Definition: txtfly.hxx:61
SwPageDesc * GetPageDesc()
Definition: pagefrm.hxx:129
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
FlyAnchors.
Definition: fmtanchr.hxx:34
SwLayoutFrame * GetUpper()
Definition: frame.hxx:656
const SwRect & GetObjRectWithSpaces() const
method to determine object area inclusive its spacing
static SwRect CalcBoundRect(const SwAnchoredObject *pAnchoredObj, const SwRect &rLine, const SwTextFrame *pFrame, const long nXPos, const bool bRight)
Computes the rectangle that will cover the object in the given line.
Definition: txtfly.cxx:154
virtual basegfx::B2DPolyPolygon TakeContour() const
bool GetTop(const SwAnchoredObject *_pAnchoredObj, const bool bInFootnote, const bool bInFooterOrHeader)
#i26945# - change first parameter Now it's the instance of the floating screen obj...
Definition: txtfly.cxx:628
sal_uInt32 GetOrdNum() const
Provides access to settings of a document.
css::text::WrapTextMode GetSurround() const
Definition: fmtsrnd.hxx:51
void DrawStretchText_(SwDrawTextInfo &rInf)
Definition: swfont.hxx:320
size
Connection (text flow) between two FlyFrames.
Definition: fmtcnct.hxx:31
SwRect AnchoredObjToRect(const SwAnchoredObject *pAnchoredObj, const SwRect &rRect) const
Determines the demanded rectangle for an anchored object, considering its surround for text wrapping...
Definition: txtfly.cxx:1255
const SdrObject * GetObject(sal_uInt16 nPos) const
Definition: txtfly.hxx:69
bool mbIgnoreContour
Definition: txtfly.hxx:134
void CalcRightMargin(SwRect &rFly, SwAnchoredObjList::size_type nPos, const SwRect &rLine) const
The right margin is the right margin or it is determined by the next object standing on the line...
Definition: txtfly.cxx:1102
void SSize(const Size &rNew)
Definition: swrect.hxx:176
long GetPrtRight(const SwFrame &rFrame) const
Definition: frame.hxx:1388
bool IsTransparent() const
Definition: notxtfrm.cxx:1286
sal_uInt16 GetCount() const
Definition: txtfly.hxx:70
long X() const
SwFlyFrameFormat * GetNext() const
Definition: fmtcnct.hxx:54
virtual SdrLayerID GetHellId() const =0
std::vector< SwAnchoredObject * > SwAnchoredObjList
Definition: txtfly.hxx:37
virtual SdrLayerID GetLayer() const
const SwPageDesc * GetFollow() const
Definition: pagedesc.hxx:246
void SetLeft(SwRect &rRect, long nNew) const
Definition: frame.hxx:1364
long GetPrtLeft(const SwFrame &rFrame) const
Definition: frame.hxx:1387
SwTextFly()
Definition: txtfly.cxx:306
SwRectGet fnGetLeft
Definition: frame.hxx:1269
const SwTextFrame * m_pCurrFrame
Definition: txtfly.hxx:123
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
SwAnchoredObjList::size_type GetPos(const SwAnchoredObject *pAnchoredObj) const
Definition: txtfly.cxx:1092
void Left(const long nLeft)
Definition: swrect.hxx:193
void Bottom(const long nBottom)
Definition: swrect.hxx:207
const SvxULSpaceItem & GetULSpace(bool=true) const
Definition: frmatr.hxx:76
std::unique_ptr< SwAnchoredObjList > mpAnchoredObjList
Definition: txtfly.hxx:125
const SwFormatChain & GetChain(bool=true) const
Definition: fmtcnct.hxx:70
bool Is_Lower_Of(const SwFrame *pCurrFrame, const SdrObject *pObj)
Definition: frmtool.cxx:3361
const SwTextFrame * GetMaster() const
Definition: txtfly.hxx:341
general base class for all free-flowing frames
Definition: flyfrm.hxx:60
::basegfx::B2DPolyPolygon getB2DPolyPolygon() const
virtual SwFrameFormat & GetFrameFormat()=0
SwTextFrame * FindMaster() const
Definition: flowfrm.cxx:679
bool supportsAutoContour() const
Definition: flylay.cxx:303
void Width(long nNew)
Definition: swrect.hxx:185
const Point & GetPos() const
Definition: drawfont.hxx:195
TextFrameIndex GetLen() const
Definition: drawfont.hxx:268
bool IsNoTextFrame() const
Definition: frame.hxx:1214
const Size & GetSize() const
Definition: drawfont.hxx:242
IDocumentSettingAccess const & getIDocumentSettingAccess() const
Definition: doc.cxx:175
bool IsRightToLeft() const
Definition: frame.hxx:963
~SwTextFly()
Definition: txtfly.cxx:349
bool ForEach(const SwRect &rRect, SwRect *pRect, bool bAvoid) const
Look for the first object which overlaps with the rectangle.
Definition: txtfly.cxx:991
const SwFrame * GetVirtualUpper(const SwFrame *pFrame, const Point &rPos)
Provides the Upper of an anchor in paragraph-bound objects.
Definition: frmtool.cxx:3329
void SetRight(SwRect &rRect, long nNew) const
Definition: frame.hxx:1365
css::text::WrapTextMode GetSurroundForTextWrap(const SwAnchoredObject *pAnchoredObj) const
Definition: txtfly.cxx:1320
#define FRAME_MAX
Definition: txtfly.cxx:1318
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:54
long GetHeight(const SwRect &rRect) const
Definition: frame.hxx:1358
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
vcl::RenderContext & GetOut() const
Definition: drawfont.hxx:180
#define FAR_AWAY
Definition: frmtool.hxx:52
void SetNextTop(long nNew) const
Definition: txtfly.hxx:351
long GetRight() const
bool IsVertical() const
Definition: frame.hxx:949
long GetTop(const SwRect &rRect) const
Definition: frame.hxx:1353
SwDoc & GetDoc()
Definition: txtfrm.hxx:450
TextFrameIndex GetIdx() const
Definition: drawfont.hxx:263
bool IsOutside() const
Definition: fmtsrnd.hxx:54
const SwFrame * GetAnchorFrame() const
SwOperator fnYDiff
Definition: frame.hxx:1313
void CtorInitTextFly(const SwTextFrame *pFrame)
Definition: txtfly.cxx:353
long nMinBottom
Definition: txtfly.hxx:127
bool IsOver(const SwRect &rRect) const
Definition: swrect.cxx:125
SwFlyFrameFormat * GetPrev() const
Definition: fmtcnct.hxx:53
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:204
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
class for collecting anchored objects
Definition: sortedobjs.hxx:48
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
SwRootFrame * getRootFrame()
Definition: frame.hxx:657
long Y() const
sal_uInt16 nPos
sal_uInt16 GetUpper() const
SwRectGet fnGetTop
Definition: frame.hxx:1267
SwFrame * GetNext()
Definition: frame.hxx:654
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74