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