android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / text / txtfly.cxx
bloba290ac4d2010bc6fc62579f90c45391fe10deaa7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/outdev.hxx>
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 "inftxt.hxx"
37 #include "porrst.hxx"
38 #include "txtpaint.hxx"
39 #include <notxtfrm.hxx>
40 #include <fmtcnct.hxx>
41 #include <svx/obj3d.hxx>
42 #include <editeng/txtrange.hxx>
43 #include <editeng/lrspitem.hxx>
44 #include <editeng/ulspitem.hxx>
45 #include <fmtsrnd.hxx>
46 #include <fmtanchr.hxx>
47 #include <frmfmt.hxx>
48 #include <fmtfollowtextflow.hxx>
49 #include <pagedesc.hxx>
50 #include <sortedobjs.hxx>
51 #include <IDocumentDrawModelAccess.hxx>
52 #include <IDocumentSettingAccess.hxx>
53 #include <formatlinebreak.hxx>
54 #include <svx/svdoedge.hxx>
56 #ifdef DBG_UTIL
57 #include <viewsh.hxx>
58 #include <doc.hxx>
59 #endif
61 using namespace ::com::sun::star;
63 namespace
65 // #i68520#
66 struct AnchoredObjOrder
68 bool mbR2L;
69 SwRectFn mfnRect;
71 AnchoredObjOrder( const bool bR2L,
72 SwRectFn fnRect )
73 : mbR2L( bR2L ),
74 mfnRect( fnRect )
77 bool operator()( const SwAnchoredObject* pListedAnchoredObj,
78 const SwAnchoredObject* pNewAnchoredObj )
80 const SwRect& aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
81 const SwRect& aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
82 if ( ( mbR2L &&
83 ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
84 (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
85 ( !mbR2L &&
86 ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
87 (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
89 SwTwips nTopDiff =
90 (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
91 (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
92 if ( nTopDiff == 0 &&
93 ( ( mbR2L &&
94 ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
95 (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
96 ( !mbR2L &&
97 ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
98 (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
100 return true;
102 else if ( nTopDiff > 0 )
104 return true;
107 else if ( ( mbR2L &&
108 ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
109 (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
110 ( !mbR2L &&
111 ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
112 (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
114 return true;
117 return false;
122 SwContourCache::SwContourCache() :
123 mnPointCount( 0 )
127 SwContourCache::~SwContourCache()
131 void SwContourCache::ClrObject( sal_uInt16 nPos )
133 mnPointCount -= mvItems[ nPos ].mxTextRanger->GetPointCount();
134 mvItems.erase(mvItems.begin() + nPos);
137 void ClrContourCache( const SdrObject *pObj )
139 if( pContourCache && pObj )
140 for( sal_uInt16 i = 0; i < pContourCache->GetCount(); ++i )
141 if( pObj == pContourCache->GetObject( i ) )
143 pContourCache->ClrObject( i );
144 break;
148 void ClrContourCache()
150 if( pContourCache )
152 pContourCache->mvItems.clear();
153 pContourCache->mnPointCount = 0;
157 // #i68520#
158 SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
159 const SwRect &rLine,
160 const SwTextFrame* pFrame,
161 const tools::Long nXPos,
162 const bool bRight )
164 SwRect aRet;
165 const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
166 bool bHandleContour(pFormat->GetSurround().IsContour());
168 if(!bHandleContour)
170 // RotateFlyFrame3: Object has no set contour, but for rotated
171 // FlyFrames we can create a 'default' contour to make text
172 // flow around the free, non-covered
173 const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(pAnchoredObj));
175 if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->supportsAutoContour())
177 bHandleContour = true;
181 if( bHandleContour &&
182 ( pAnchoredObj->DynCastFlyFrame() == nullptr ||
183 ( static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower() &&
184 static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower()->IsNoTextFrame() ) ) )
186 aRet = pAnchoredObj->GetObjRectWithSpaces();
187 if( aRet.Overlaps( rLine ) )
189 if( !pContourCache )
190 pContourCache = new SwContourCache;
192 aRet = pContourCache->ContourRect(
193 pFormat, pAnchoredObj->GetDrawObj(), pFrame, rLine, nXPos, bRight );
195 else
196 aRet.Width( 0 );
198 else
200 aRet = pAnchoredObj->GetObjRectWithSpaces();
203 return aRet;
206 SwRect SwContourCache::ContourRect( const SwFormat* pFormat,
207 const SdrObject* pObj, const SwTextFrame* pFrame, const SwRect &rLine,
208 const tools::Long nXPos, const bool bRight )
210 SwRect aRet;
211 sal_uInt16 nPos = 0; // Search in the Cache
212 while( nPos < GetCount() && pObj != mvItems[ nPos ].mpSdrObj )
213 ++nPos;
214 if( GetCount() == nPos ) // Not found
216 if( GetCount() == POLY_CNT )
218 mnPointCount -= mvItems.back().mxTextRanger->GetPointCount();
219 mvItems.pop_back();
221 ::basegfx::B2DPolyPolygon aPolyPolygon;
222 std::optional<::basegfx::B2DPolyPolygon> pPolyPolygon;
224 if ( auto pVirtFlyDrawObj = dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) )
226 // GetContour() causes the graphic to be loaded, which may cause
227 // the graphic to change its size, call ClrObject()
228 tools::PolyPolygon aPoly;
229 if( !pVirtFlyDrawObj->GetFlyFrame()->GetContour( aPoly ) )
230 aPoly = tools::PolyPolygon( pVirtFlyDrawObj->
231 GetFlyFrame()->getFrameArea().SVRect() );
232 aPolyPolygon.clear();
233 aPolyPolygon.append(aPoly.getB2DPolyPolygon());
235 else
237 if( DynCastE3dObject( pObj ) == nullptr )
239 aPolyPolygon = pObj->TakeXorPoly();
242 pPolyPolygon = pObj->TakeContour();
244 const SvxLRSpaceItem &rLRSpace = pFormat->GetLRSpace();
245 const SvxULSpaceItem &rULSpace = pFormat->GetULSpace();
246 CacheItem item {
247 pObj, // due to #37347 the Object must be entered only after GetContour()
248 std::make_unique<TextRanger>( aPolyPolygon, pPolyPolygon ? &*pPolyPolygon : nullptr, 20,
249 o3tl::narrowing<sal_uInt16>(rLRSpace.GetLeft()), o3tl::narrowing<sal_uInt16>(rLRSpace.GetRight()),
250 pFormat->GetSurround().IsOutside(), false, pFrame->IsVertical() )
252 mvItems.insert(mvItems.begin(), std::move(item));
253 mvItems[0].mxTextRanger->SetUpper( rULSpace.GetUpper() );
254 mvItems[0].mxTextRanger->SetLower( rULSpace.GetLower() );
256 pPolyPolygon.reset();
258 mnPointCount += mvItems[0].mxTextRanger->GetPointCount();
259 while( mnPointCount > POLY_MAX && mvItems.size() > POLY_MIN )
261 mnPointCount -= mvItems.back().mxTextRanger->GetPointCount();
262 mvItems.pop_back();
265 else if( nPos )
267 CacheItem item = std::move(mvItems[nPos]);
268 mvItems.erase(mvItems.begin() + nPos);
269 mvItems.insert(mvItems.begin(), std::move(item));
271 SwRectFnSet aRectFnSet(pFrame);
272 tools::Long nTmpTop = aRectFnSet.GetTop(rLine);
273 // fnGetBottom is top + height
274 tools::Long nTmpBottom = aRectFnSet.GetBottom(rLine);
276 Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );
278 std::deque<tools::Long>* pTmp = mvItems[0].mxTextRanger->GetTextRanges( aRange );
280 const size_t nCount = pTmp->size();
281 if( 0 != nCount )
283 size_t nIdx = 0;
284 while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
285 ++nIdx;
286 bool bOdd = nIdx % 2;
287 bool bSet = true;
288 if( bOdd )
289 --nIdx; // within interval
290 else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
292 if( nIdx )
293 nIdx -= 2; // an interval to the left
294 else
295 bSet = false; // before the first interval
298 if( bSet && nIdx < nCount )
300 aRectFnSet.SetTopAndHeight( aRet, aRectFnSet.GetTop(rLine),
301 aRectFnSet.GetHeight(rLine) );
302 aRectFnSet.SetLeft( aRet, (*pTmp)[ nIdx ] );
303 aRectFnSet.SetRight( aRet, (*pTmp)[ nIdx + 1 ] + 1 );
306 return aRet;
309 SwTextFly::SwTextFly()
310 : m_pPage(nullptr)
311 , mpCurrAnchoredObj(nullptr)
312 , m_pCurrFrame(nullptr)
313 , m_pMaster(nullptr)
314 , m_nMinBottom(0)
315 , m_nNextTop(0)
316 , m_nCurrFrameNodeIndex(0)
317 , m_bOn(false)
318 , m_bTopRule(false)
319 , mbIgnoreCurrentFrame(false)
320 , mbIgnoreContour(false)
321 , mbIgnoreObjsInHeaderFooter(false)
326 SwTextFly::SwTextFly( const SwTextFrame *pFrame )
328 CtorInitTextFly( pFrame );
331 SwTextFly::SwTextFly( const SwTextFly& rTextFly )
333 m_pPage = rTextFly.m_pPage;
334 mpCurrAnchoredObj = rTextFly.mpCurrAnchoredObj;
335 m_pCurrFrame = rTextFly.m_pCurrFrame;
336 m_pMaster = rTextFly.m_pMaster;
337 if( rTextFly.mpAnchoredObjList )
339 mpAnchoredObjList.reset( new SwAnchoredObjList( *(rTextFly.mpAnchoredObjList) ) );
342 m_bOn = rTextFly.m_bOn;
343 m_bTopRule = rTextFly.m_bTopRule;
344 m_nMinBottom = rTextFly.m_nMinBottom;
345 m_nNextTop = rTextFly.m_nNextTop;
346 m_nCurrFrameNodeIndex = rTextFly.m_nCurrFrameNodeIndex;
347 mbIgnoreCurrentFrame = rTextFly.mbIgnoreCurrentFrame;
348 mbIgnoreContour = rTextFly.mbIgnoreContour;
349 mbIgnoreObjsInHeaderFooter = rTextFly.mbIgnoreObjsInHeaderFooter;
352 SwTextFly::~SwTextFly()
356 void SwTextFly::CtorInitTextFly( const SwTextFrame *pFrame )
358 mbIgnoreCurrentFrame = false;
359 mbIgnoreContour = false;
360 mbIgnoreObjsInHeaderFooter = false;
361 m_pPage = pFrame->FindPageFrame();
362 const SwFlyFrame* pTmp = pFrame->FindFlyFrame();
363 // #i68520#
364 mpCurrAnchoredObj = pTmp;
365 m_pCurrFrame = pFrame;
366 m_pMaster = m_pCurrFrame->IsFollow() ? nullptr : m_pCurrFrame;
367 // If we're not overlapped by a frame or if a FlyCollection does not exist
368 // at all, we switch off forever.
369 // It could be, however, that a line is added while formatting, that
370 // extends into a frame.
371 // That's why we do not optimize for: bOn = pSortedFlys && IsAnyFrame();
372 m_bOn = m_pPage->GetSortedObjs() != nullptr;
373 m_bTopRule = true;
374 m_nMinBottom = 0;
375 m_nNextTop = 0;
376 m_nCurrFrameNodeIndex = NODE_OFFSET_MAX;
379 SwRect SwTextFly::GetFrame_( const SwRect &rRect ) const
381 SwRect aRet;
382 if( ForEach( rRect, &aRet, true ) )
384 SwRectFnSet aRectFnSet(m_pCurrFrame);
385 aRectFnSet.SetTop( aRet, aRectFnSet.GetTop(rRect) );
387 // Do not always adapt the bottom
388 const SwTwips nRetBottom = aRectFnSet.GetBottom(aRet);
389 const SwTwips nRectBottom = aRectFnSet.GetBottom(rRect);
390 if ( aRectFnSet.YDiff( nRetBottom, nRectBottom ) > 0 ||
391 aRectFnSet.GetHeight(aRet) < 0 )
392 aRectFnSet.SetBottom( aRet, nRectBottom );
394 return aRet;
397 bool SwTextFly::IsAnyFrame() const
399 SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
401 OSL_ENSURE( m_bOn, "IsAnyFrame: Why?" );
402 SwRect aRect(m_pCurrFrame->getFrameArea().Pos() + m_pCurrFrame->getFramePrintArea().Pos(),
403 m_pCurrFrame->getFramePrintArea().SSize());
405 return ForEach( aRect, nullptr, false );
408 bool SwTextFly::IsAnyObj( const SwRect &rRect ) const
410 OSL_ENSURE( m_bOn, "SwTextFly::IsAnyObj: Who's knocking?" );
412 SwRect aRect( rRect );
413 if ( aRect.IsEmpty() )
415 aRect = SwRect(m_pCurrFrame->getFrameArea().Pos() + m_pCurrFrame->getFramePrintArea().Pos(),
416 m_pCurrFrame->getFramePrintArea().SSize());
418 SwTwips nLower = m_pCurrFrame->GetLowerMarginForFlyIntersect();
419 if (nLower > 0)
421 aRect.AddBottom(nLower);
425 const SwSortedObjs *pSorted = m_pPage->GetSortedObjs();
426 if( pSorted ) // bOn actually makes sure that we have objects on the side,
427 // but who knows who deleted something in the meantime?
429 for ( size_t i = 0; i < pSorted->size(); ++i )
431 const SwAnchoredObject* pObj = (*pSorted)[i];
433 const SwRect aBound( pObj->GetObjRectWithSpaces() );
435 // Optimization
436 if( pObj->GetObjRect().Left() > aRect.Right() )
437 continue;
439 // #i68520#
440 if( mpCurrAnchoredObj != pObj && aBound.Overlaps( aRect ) )
441 return true;
444 return false;
447 const SwTextFrame* SwTextFly::GetMaster_()
449 m_pMaster = m_pCurrFrame;
450 while (m_pMaster && m_pMaster->IsFollow())
451 m_pMaster = m_pMaster->FindMaster();
452 return m_pMaster;
455 void SwTextFly::DrawTextOpaque( SwDrawTextInfo &rInf )
457 SwSaveClip aClipSave( rInf.GetpOut() );
458 SwRect aRect( rInf.GetPos(), rInf.GetSize() );
459 if( rInf.GetSpace() )
461 TextFrameIndex const nTmpLen = TextFrameIndex(COMPLETE_STRING) == rInf.GetLen()
462 ? TextFrameIndex(rInf.GetText().getLength())
463 : rInf.GetLen();
464 if( rInf.GetSpace() > 0 )
466 sal_Int32 nSpaceCnt = 0;
467 const TextFrameIndex nEndPos = rInf.GetIdx() + nTmpLen;
468 for (TextFrameIndex nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos)
470 if (CH_BLANK == rInf.GetText()[sal_Int32(nPos)])
471 ++nSpaceCnt;
473 if( nSpaceCnt )
474 aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
476 else
477 aRect.Width( aRect.Width() - sal_Int32(nTmpLen) * rInf.GetSpace() );
480 if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
482 SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
483 aRect.Intersection( aClipRect );
486 SwRegionRects aRegion( aRect );
488 bool bOpaque = false;
489 // #i68520#
490 const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
491 ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
492 : SAL_MAX_UINT32;
493 OSL_ENSURE( !m_bTopRule, "DrawTextOpaque: Wrong TopRule" );
495 // #i68520#
496 const SwAnchoredObjList::size_type nCount( m_bOn ? GetAnchoredObjList()->size() : 0 );
497 if (nCount > 0)
499 const SdrLayerID nHellId = m_pPage->getRootFrame()->GetCurrShell()->getIDocumentDrawModelAccess().GetHellId();
500 for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
502 // #i68520#
503 const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
504 const SwFlyFrame* pFly = pTmpAnchoredObj->DynCastFlyFrame();
505 if( pFly && mpCurrAnchoredObj != pTmpAnchoredObj )
507 // #i68520#
508 if( aRegion.GetOrigin().Overlaps( pFly->getFrameArea() ) )
510 const SwFrameFormat *pFormat = pFly->GetFormat();
511 const SwFormatSurround &rSur = pFormat->GetSurround();
512 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
513 // Only the ones who are opaque and more to the top
514 if( ! pFly->IsBackgroundTransparent() &&
515 css::text::WrapTextMode_THROUGH == rSur.GetSurround() &&
516 ( !rSur.IsAnchorOnly() ||
517 // #i68520#
518 GetMaster() == pFly->GetAnchorFrame() ||
519 ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
520 (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId())
522 ) &&
523 // #i68520#
524 pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
525 nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
528 // Except for the content is transparent
529 const SwNoTextFrame *pNoText =
530 pFly->Lower() && pFly->Lower()->IsNoTextFrame()
531 ? static_cast<const SwNoTextFrame*>(pFly->Lower())
532 : nullptr;
533 if ( !pNoText ||
534 (!pNoText->IsTransparent() && !rSur.IsContour()) )
536 bOpaque = true;
537 aRegion -= pFly->getFrameArea();
545 Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
546 const Point aOldPos(rInf.GetPos());
547 rInf.SetPos( aPos );
549 if( !bOpaque )
551 if( rInf.GetKern() )
552 rInf.GetFont()->DrawStretchText_( rInf );
553 else
554 rInf.GetFont()->DrawText_( rInf );
555 rInf.SetPos(aOldPos);
556 return;
558 else if( !aRegion.empty() )
560 // What a huge effort ...
561 SwSaveClip aClipVout( rInf.GetpOut() );
562 for( size_t i = 0; i < aRegion.size(); ++i )
564 SwRect &rRect = aRegion[i];
565 if( rRect != aRegion.GetOrigin() )
566 aClipVout.ChgClip( rRect );
567 if( rInf.GetKern() )
568 rInf.GetFont()->DrawStretchText_( rInf );
569 else
570 rInf.GetFont()->DrawText_( rInf );
573 rInf.SetPos(aOldPos);
576 void SwTextFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect )
578 SwRegionRects aRegion( rRect );
579 OSL_ENSURE( !m_bTopRule, "DrawFlyRect: Wrong TopRule" );
580 // #i68520#
581 const SwAnchoredObjList::size_type nCount( m_bOn ? GetAnchoredObjList()->size() : 0 );
582 if (nCount > 0)
584 const SdrLayerID nHellId = m_pPage->getRootFrame()->GetCurrShell()->getIDocumentDrawModelAccess().GetHellId();
585 for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
587 // #i68520#
588 const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
589 if (mpCurrAnchoredObj == pAnchoredObjTmp)
590 continue;
592 // #i68520#
593 const SwFlyFrame* pFly = pAnchoredObjTmp->DynCastFlyFrame();
594 if (pFly)
596 // #i68520#
597 const SwFormatSurround& rSur = pAnchoredObjTmp->GetFrameFormat().GetSurround();
599 // OD 24.01.2003 #106593# - correct clipping of fly frame area.
600 // Consider that fly frame background/shadow can be transparent
601 // and <SwAlignRect(..)> fly frame area
602 // #i47804# - consider transparent graphics
603 // and OLE objects.
604 bool bClipFlyArea =
605 ( ( css::text::WrapTextMode_THROUGH == rSur.GetSurround() )
606 // #i68520#
607 ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
608 : !rSur.IsContour() ) &&
609 !pFly->IsBackgroundTransparent() &&
610 ( !pFly->Lower() ||
611 !pFly->Lower()->IsNoTextFrame() ||
612 !static_cast<const SwNoTextFrame*>(pFly->Lower())->IsTransparent() );
613 if ( bClipFlyArea )
615 // #i68520#
616 SwRect aFly( pAnchoredObjTmp->GetObjRect() );
617 // OD 24.01.2003 #106593#
618 ::SwAlignRect( aFly, m_pPage->getRootFrame()->GetCurrShell(), pOut );
619 if( !aFly.IsEmpty() )
620 aRegion -= aFly;
626 for( size_t i = 0; i < aRegion.size(); ++i )
628 pOut->DrawRect( aRegion[i].SVRect() );
633 * #i26945# - change first parameter
634 * Now it's the <SwAnchoredObject> instance of the floating screen object
636 bool SwTextFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
637 const bool bInFootnote,
638 const bool bInFooterOrHeader )
640 // #i68520#
641 // <mpCurrAnchoredObj> is set, if <m_pCurrFrame> is inside a fly frame
642 if( _pAnchoredObj != mpCurrAnchoredObj )
644 // #i26945#
645 const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
646 // #102344# Ignore connectors which have one or more connections
647 if (const SdrEdgeObj* pEdgeObj = dynamic_cast<const SdrEdgeObj*>(pNew))
649 if (pEdgeObj->GetConnectedNode(true) || pEdgeObj->GetConnectedNode(false))
651 return false;
655 if( ( bInFootnote || bInFooterOrHeader ) && m_bTopRule )
657 // #i26945#
658 const SwFrameFormat& rFrameFormat = _pAnchoredObj->GetFrameFormat();
659 const SwFormatAnchor& rNewA = rFrameFormat.GetAnchor();
660 if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
662 if ( bInFootnote )
663 return false;
665 if ( bInFooterOrHeader )
667 const SwFormatVertOrient& aVert( rFrameFormat.GetVertOrient() );
668 bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
669 aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
670 if( bVertPrt )
671 return false;
676 // #i68520#
677 // bEvade: consider pNew, if we are not inside a fly
678 // consider pNew, if pNew is lower of <mpCurrAnchoredObj>
679 bool bEvade = !mpCurrAnchoredObj ||
680 Is_Lower_Of( mpCurrAnchoredObj->DynCastFlyFrame(), pNew);
682 auto pFly = _pAnchoredObj->DynCastFlyFrame();
683 if (pFly && pFly->IsFlySplitAllowed())
685 // Check if _pAnchoredObj is a split fly inside an other split fly. Always collect such
686 // flys, otherwise the inner anchor text will overlap with the inner fly.
687 SwFrame* pFlyAnchor = const_cast<SwAnchoredObject*>(_pAnchoredObj)
688 ->GetAnchorFrameContainingAnchPos();
689 if (pFlyAnchor && pFlyAnchor->IsInFly())
691 auto pOuterFly = pFlyAnchor->FindFlyFrame();
692 if (pOuterFly && pOuterFly->IsFlySplitAllowed())
694 return true;
699 if ( !bEvade )
701 // We are currently inside a fly frame and pNew is not
702 // inside this fly frame. We can do some more checks if
703 // we have to consider pNew.
705 // If bTopRule is not set, we ignore the frame types.
706 // We directly check the z-order
707 if ( !m_bTopRule )
708 bEvade = true;
709 else
711 // Within chained Flys we only avoid Lower
712 // #i68520#
713 const SwFormatChain &rChain = mpCurrAnchoredObj->GetFrameFormat().GetChain();
714 if ( !rChain.GetPrev() && !rChain.GetNext() )
716 // #i26945#
717 const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat().GetAnchor();
718 // #i68520#
719 const SwFormatAnchor& rCurrA = mpCurrAnchoredObj->GetFrameFormat().GetAnchor();
721 // If <mpCurrAnchoredObj> is anchored as character, its content
722 // does not wrap around pNew
723 if (RndStdIds::FLY_AS_CHAR == rCurrA.GetAnchorId())
724 return false;
726 // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
727 // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
728 // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
729 // some more checks
730 if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
732 if (RndStdIds::FLY_AT_PAGE == rCurrA.GetAnchorId())
734 bEvade = true;
736 else
737 return false;
739 else if (RndStdIds::FLY_AT_PAGE == rCurrA.GetAnchorId())
740 return false; // Page anchored ones only avoid page anchored ones
741 else if (RndStdIds::FLY_AT_FLY == rNewA.GetAnchorId())
742 bEvade = true; // Non-page anchored ones avoid frame anchored ones
743 else if( RndStdIds::FLY_AT_FLY == rCurrA.GetAnchorId() )
744 return false; // Frame anchored ones do not avoid paragraph anchored ones
745 // #i57062#
746 // In order to avoid loop situation, it's decided to adjust
747 // the wrapping behaviour of content of at-paragraph/at-character
748 // anchored objects to one in the page header/footer and
749 // the document body --> content of at-paragraph/at-character
750 // anchored objects doesn't wrap around each other.
751 else
752 return false;
756 // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
757 // #i68520#
758 bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
759 if( bEvade )
761 // #i68520#
762 const SwRect& aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
763 if ( !aTmp.Overlaps( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
764 bEvade = false;
768 if ( bEvade )
770 // #i26945#
771 const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat().GetAnchor();
772 OSL_ENSURE( RndStdIds::FLY_AS_CHAR != rNewA.GetAnchorId(),
773 "Don't call GetTop with a FlyInContentFrame" );
774 if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
775 return true; // We always avoid page anchored ones
777 // If Flys anchored at paragraph are caught in a FlyCnt, then
778 // their influence ends at the borders of the FlyCnt!
779 // If we are currently formatting the text of the FlyCnt, then
780 // it has to get out of the way of the Frame anchored at paragraph!
781 // m_pCurrFrame is the anchor of pNew?
782 // #i26945#
783 const SwFrame* pTmp = _pAnchoredObj->GetAnchorFrame();
784 if (pTmp == m_pCurrFrame)
785 return true;
786 if( pTmp->IsTextFrame() && ( pTmp->IsInFly() || pTmp->IsInFootnote() ) )
788 // #i26945#
789 Point aPos = _pAnchoredObj->GetObjRect().Pos();
790 pTmp = GetVirtualUpper( pTmp, aPos );
792 // #i26945#
793 // If <pTmp> is a text frame inside a table, take the upper
794 // of the anchor frame, which contains the anchor position.
795 else if ( pTmp->IsTextFrame() && pTmp->IsInTab() )
797 pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
798 ->GetAnchorFrameContainingAnchPos()->GetUpper();
800 // #i28701# - consider all objects in same context,
801 // if wrapping style is considered on object positioning.
802 // Thus, text will wrap around negative positioned objects.
803 // #i3317# - remove condition on checking,
804 // if wrappings style is considered on object positioning.
805 // Thus, text is wrapping around negative positioned objects.
806 // #i35640# - no consideration of negative
807 // positioned objects, if wrapping style isn't considered on
808 // object position and former text wrapping is applied.
809 // This condition is typically for documents imported from the
810 // OpenOffice.org file format.
811 const IDocumentSettingAccess* pIDSA = &m_pCurrFrame->GetDoc().getIDocumentSettingAccess();
812 if ( ( pIDSA->get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
813 !pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ) &&
814 ::FindContext( pTmp, SwFrameType::None ) == ::FindContext(m_pCurrFrame, SwFrameType::None))
816 return true;
819 const SwFrame* pHeader = nullptr;
820 if (m_pCurrFrame->GetNext() != pTmp &&
821 (IsFrameInSameContext( pTmp, m_pCurrFrame ) ||
822 // #i13832#, #i24135# wrap around objects in page header
823 ( !pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) &&
824 nullptr != ( pHeader = pTmp->FindFooterOrHeader() ) &&
825 m_pCurrFrame->IsInDocBody())))
827 if( pHeader || RndStdIds::FLY_AT_FLY == rNewA.GetAnchorId() )
828 return true;
830 // Compare indices:
831 // The Index of the other is retrieved from the anchor attr.
832 SwNodeOffset nTmpIndex = rNewA.GetAnchorNode()->GetIndex();
833 // Now check whether the current paragraph is before the anchor
834 // of the displaced object in the text, then we don't have to
835 // get out of its way.
836 // If possible determine Index via SwFormatAnchor because
837 // otherwise it's quite expensive.
838 if (NODE_OFFSET_MAX == m_nCurrFrameNodeIndex)
839 m_nCurrFrameNodeIndex = m_pCurrFrame->GetTextNodeFirst()->GetIndex();
841 if (FrameContainsNode(*m_pCurrFrame, nTmpIndex) || nTmpIndex < m_nCurrFrameNodeIndex)
842 return true;
846 return false;
849 SwRect SwTextFly::GetFrameArea() const
851 // i#28701 - consider complete frame area for new text wrapping
852 SwRect aRect;
853 if (m_pCurrFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING))
855 aRect = m_pCurrFrame->getFramePrintArea();
856 aRect += m_pCurrFrame->getFrameArea().Pos();
858 else
860 aRect = m_pCurrFrame->getFrameArea();
862 return aRect;
865 // #i68520#
866 SwAnchoredObjList* SwTextFly::InitAnchoredObjList()
868 OSL_ENSURE( m_pCurrFrame, "InitFlyList: No Frame, no FlyList" );
869 // #i68520#
870 OSL_ENSURE( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
872 SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
874 const SwSortedObjs *pSorted = m_pPage->GetSortedObjs();
875 const size_t nCount = pSorted ? pSorted->size() : 0;
876 // --> #108724# Page header/footer content doesn't have to wrap around
877 // floating screen objects
878 // which was added simply to be compatible with MS Office.
879 // MSO still allows text to wrap around in-table-flies in headers/footers/footnotes
880 const bool bFooterHeader = nullptr != m_pCurrFrame->FindFooterOrHeader();
881 const IDocumentSettingAccess* pIDSA = &m_pCurrFrame->GetDoc().getIDocumentSettingAccess();
882 // #i40155# - check, if frame is marked not to wrap
883 const bool bAllowCompatWrap = m_pCurrFrame->IsInTab() && (bFooterHeader || m_pCurrFrame->IsInFootnote());
884 const bool bWrapAllowed = ( pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ||
885 bAllowCompatWrap ||
886 (!m_pCurrFrame->IsInFootnote() && !bFooterHeader));
888 m_bOn = false;
890 if( nCount && bWrapAllowed )
892 // #i68520#
893 mpAnchoredObjList.reset(new SwAnchoredObjList );
895 SwRect const aRect(GetFrameArea());
896 // Make ourselves a little smaller than we are,
897 // so that 1-Twip-overlappings are ignored (#49532)
898 SwRectFnSet aRectFnSet(m_pCurrFrame);
899 const tools::Long nRight = aRectFnSet.GetRight(aRect) - 1;
900 const tools::Long nLeft = aRectFnSet.GetLeft(aRect) + 1;
901 const bool bR2L = m_pCurrFrame->IsRightToLeft();
903 const IDocumentDrawModelAccess& rIDDMA = m_pCurrFrame->GetDoc().getIDocumentDrawModelAccess();
905 for( size_t i = 0; i < nCount; ++i )
907 // #i68520#
908 // do not consider hidden objects
909 // check, if object has to be considered for text wrap
910 // #118809# - If requested, do not consider
911 // objects in page header|footer for text frames not in page
912 // header|footer. This is requested for the calculation of
913 // the base offset for objects <SwTextFrame::CalcBaseOfstForFly()>
914 // #i20505# Do not consider oversized objects
915 SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
916 assert(pAnchoredObj);
917 if ( !pAnchoredObj ||
918 !rIDDMA.IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
919 !pAnchoredObj->ConsiderForTextWrap() ||
920 ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
921 pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() ) ||
922 ( bAllowCompatWrap && !pAnchoredObj->GetFrameFormat().GetFollowTextFlow().GetValue() )
925 continue;
928 const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
929 if ( nRight < aRectFnSet.GetLeft(aBound) ||
930 aRectFnSet.YDiff( aRectFnSet.GetTop(aRect),
931 aRectFnSet.GetBottom(aBound) ) > 0 ||
932 nLeft > aRectFnSet.GetRight(aBound) ||
933 aRectFnSet.GetHeight(aBound) >
934 2 * aRectFnSet.GetHeight(m_pPage->getFrameArea()) )
936 continue;
939 // #i26945# - pass <pAnchoredObj> to method
940 // <GetTop(..)> instead of only the <SdrObject> instance of the
941 // anchored object
942 if (GetTop(pAnchoredObj, m_pCurrFrame->IsInFootnote(), bFooterHeader))
944 // OD 11.03.2003 #107862# - adjust insert position:
945 // overlapping objects should be sorted from left to right and
946 // inside left to right sorting from top to bottom.
947 // If objects on the same position are found, they are sorted
948 // on its width.
949 // #i68520#
951 SwAnchoredObjList::iterator aInsPosIter =
952 std::lower_bound( mpAnchoredObjList->begin(),
953 mpAnchoredObjList->end(),
954 pAnchoredObj,
955 AnchoredObjOrder( bR2L, aRectFnSet.FnRect() ) );
957 mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
960 const SwFormatSurround &rFlyFormat = pAnchoredObj->GetFrameFormat().GetSurround();
961 // #i68520#
962 if ( rFlyFormat.IsAnchorOnly() &&
963 pAnchoredObj->GetAnchorFrame() == GetMaster() )
965 const SwFormatVertOrient &rTmpFormat =
966 pAnchoredObj->GetFrameFormat().GetVertOrient();
967 if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
968 m_nMinBottom = ( aRectFnSet.IsVert() && m_nMinBottom ) ?
969 std::min( m_nMinBottom, aBound.Left() ) :
970 std::max( m_nMinBottom, aRectFnSet.GetBottom(aBound) );
973 m_bOn = true;
976 if( m_nMinBottom )
978 SwTwips nMax = aRectFnSet.GetPrtBottom(*m_pCurrFrame->GetUpper());
979 if( aRectFnSet.YDiff( m_nMinBottom, nMax ) > 0 )
980 m_nMinBottom = nMax;
983 else
985 // #i68520#
986 mpAnchoredObjList.reset( new SwAnchoredObjList );
989 // #i68520#
990 return mpAnchoredObjList.get();
993 SwTwips SwTextFly::CalcMinBottom() const
995 SwTwips nRet = 0;
996 const SwContentFrame *pLclMaster = GetMaster();
997 OSL_ENSURE(pLclMaster, "SwTextFly without master");
998 const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : nullptr;
999 const size_t nCount = pDrawObj ? pDrawObj->size() : 0;
1000 if( nCount )
1002 SwTwips nEndOfFrame = m_pCurrFrame->getFrameArea().Bottom();
1003 for( size_t i = 0; i < nCount; ++i )
1005 SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
1006 const SwFormatSurround &rFlyFormat = pAnchoredObj->GetFrameFormat().GetSurround();
1007 if( rFlyFormat.IsAnchorOnly() )
1009 const SwFormatVertOrient &rTmpFormat =
1010 pAnchoredObj->GetFrameFormat().GetVertOrient();
1011 if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
1013 const SwRect& aBound( pAnchoredObj->GetObjRectWithSpaces() );
1014 if( aBound.Top() < nEndOfFrame )
1015 nRet = std::max( nRet, SwTwips(aBound.Bottom()) );
1019 SwTwips nMax = m_pCurrFrame->GetUpper()->getFrameArea().Top() +
1020 m_pCurrFrame->GetUpper()->getFramePrintArea().Bottom();
1021 if( nRet > nMax )
1022 nRet = nMax;
1024 return nRet;
1027 SwTwips SwTextFly::GetMaxBottom(const SwBreakPortion& rPortion, const SwTextFormatInfo& rInfo) const
1029 // Note that m_pCurrFrame is already swapped at this stage, so it's correct to bypass
1030 // SwRectFnSet here.
1031 SwTwips nRet = 0;
1032 size_t nCount(m_bOn ? GetAnchoredObjList()->size() : 0);
1034 // Get the horizontal position of the break portion in absolute twips. The frame area is in
1035 // absolute twips, the frame's print area is relative to the frame area. Finally the portion's
1036 // position is relative to the frame's print area.
1037 SwTwips nX = rInfo.X();
1038 nX += m_pCurrFrame->getFrameArea().Left();
1039 nX += m_pCurrFrame->getFramePrintArea().Left();
1041 for (size_t i = 0; i < nCount; ++i)
1043 const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1045 if (pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader())
1047 // Anchored in the header or footer, ignore it for clearing break purposes.
1048 continue;
1051 SwRect aRect(pAnchoredObj->GetObjRectWithSpaces());
1053 if (m_pCurrFrame->IsVertical())
1055 m_pCurrFrame->SwitchVerticalToHorizontal(aRect);
1058 if (rPortion.GetClear() == SwLineBreakClear::LEFT)
1060 if (nX < aRect.Left())
1062 // Want to jump down to the first line that's unblocked on the left. This object is
1063 // on the right of the break, ignore it.
1064 continue;
1067 if (rPortion.GetClear() == SwLineBreakClear::RIGHT)
1069 if (nX > aRect.Right())
1071 // Want to jump down to the first line that's unblocked on the right. This object is
1072 // on the left of the break, ignore it.
1073 continue;
1076 SwTwips nBottom = aRect.Top() + aRect.Height();
1077 if (nBottom > nRet)
1079 nRet = nBottom;
1082 return nRet;
1085 bool SwTextFly::ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const
1087 SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
1089 // Optimization
1090 SwRectFnSet aRectFnSet(m_pCurrFrame);
1092 // tdf#127235 stop if the area is larger than the page
1093 if( aRectFnSet.GetHeight(m_pPage->getFrameArea()) < aRectFnSet.GetHeight(rRect))
1095 // get the doc model description
1096 const SwPageDesc* pPageDesc = m_pPage->GetPageDesc();
1098 // if there is no next page style or it is the same as the current
1099 // => stop trying to place the frame (it would end in an infinite loop)
1100 if( pPageDesc &&
1101 ( !pPageDesc->GetFollow() || pPageDesc->GetFollow() == pPageDesc) )
1103 return false;
1107 bool bRet = false;
1108 // #i68520#
1109 const SwAnchoredObjList::size_type nCount( m_bOn ? GetAnchoredObjList()->size() : 0 );
1110 if (nCount > 0)
1112 for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1114 // #i68520#
1115 const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1117 SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1119 if( aRectFnSet.GetLeft(aRect) > aRectFnSet.GetRight(rRect) )
1120 break;
1122 // #i68520#
1123 if ( mpCurrAnchoredObj != pAnchoredObj && aRect.Overlaps( rRect ) )
1125 // #i68520#
1126 const SwFormat* pFormat( &(pAnchoredObj->GetFrameFormat()) );
1127 const SwFormatSurround &rSur = pFormat->GetSurround();
1128 if( bAvoid )
1130 // If the text flows below, it has no influence on
1131 // formatting. In LineIter::DrawText() it is "just"
1132 // necessary to cleverly set the ClippingRegions
1133 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1134 if( ( css::text::WrapTextMode_THROUGH == rSur.GetSurround() &&
1135 ( !rSur.IsAnchorOnly() ||
1136 // #i68520#
1137 GetMaster() == pAnchoredObj->GetAnchorFrame() ||
1138 ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
1139 (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
1140 || aRect.Top() == FAR_AWAY )
1141 continue;
1144 // #i58642#
1145 // Compare <GetMaster()> instead of <m_pCurrFrame> with the
1146 // anchor frame of the anchored object, because a follow frame
1147 // has to ignore the anchored objects of its master frame.
1148 // Note: Anchored objects are always registered at the master
1149 // frame, exception are as-character anchored objects,
1150 // but these aren't handled here.
1151 // #i68520#
1152 if ( mbIgnoreCurrentFrame &&
1153 GetMaster() == pAnchoredObj->GetAnchorFrame() )
1154 continue;
1156 if( pRect )
1158 // #i68520#
1159 SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
1160 if( aFly.IsEmpty() || !aFly.Overlaps( rRect ) )
1161 continue;
1162 if( !bRet || (
1163 (!m_pCurrFrame->IsRightToLeft() &&
1164 ( aRectFnSet.GetLeft(aFly) <
1165 aRectFnSet.GetLeft(*pRect) ) ) ||
1166 (m_pCurrFrame->IsRightToLeft() &&
1167 ( aRectFnSet.GetRight(aFly) >
1168 aRectFnSet.GetRight(*pRect) ) ) ) )
1169 *pRect = aFly;
1170 if( rSur.IsContour() )
1172 bRet = true;
1173 continue;
1176 bRet = true;
1177 break;
1182 return bRet;
1185 // #i68520#
1186 SwAnchoredObjList::size_type SwTextFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
1188 SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
1189 SwAnchoredObjList::size_type nRet = 0;
1190 while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
1191 ++nRet;
1192 return nRet;
1195 // #i68520#
1196 void SwTextFly::CalcRightMargin( SwRect &rFly,
1197 SwAnchoredObjList::size_type nFlyPos,
1198 const SwRect &rLine ) const
1200 // Usually the right margin is the right margin of the Printarea
1201 OSL_ENSURE( !m_pCurrFrame->IsVertical() || !m_pCurrFrame->IsSwapped(),
1202 "SwTextFly::CalcRightMargin with swapped frame" );
1203 SwRectFnSet aRectFnSet(m_pCurrFrame);
1204 // #118796# - correct determination of right of printing area
1205 SwTwips nRight = aRectFnSet.GetPrtRight(*m_pCurrFrame);
1206 SwTwips nFlyRight = aRectFnSet.GetRight(rFly);
1207 SwRect aLine( rLine );
1208 aRectFnSet.SetRight( aLine, nRight );
1209 aRectFnSet.SetLeft( aLine, aRectFnSet.GetLeft(rFly) );
1211 // It is possible that there is another object that is _above_ us
1212 // and protrudes into the same line.
1213 // Flys with run-through are invisible for those below, i.e., they
1214 // are ignored for computing the margins of other Flys.
1215 // 3301: pNext->getFrameArea().Overlaps( rLine ) is necessary
1216 // #i68520#
1217 css::text::WrapTextMode eSurroundForTextWrap;
1219 bool bStop = false;
1220 // #i68520#
1221 SwAnchoredObjList::size_type nPos = 0;
1223 // #i68520#
1224 while( nPos < mpAnchoredObjList->size() && !bStop )
1226 if( nPos == nFlyPos )
1228 ++nPos;
1229 continue;
1231 // #i68520#
1232 const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
1233 if ( pNext == mpCurrAnchoredObj )
1234 continue;
1235 eSurroundForTextWrap = GetSurroundForTextWrap( pNext );
1236 if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap )
1237 continue;
1239 const SwRect aTmp( SwContourCache::CalcBoundRect
1240 ( pNext, aLine, m_pCurrFrame, nFlyRight, true ) );
1241 SwTwips nTmpRight = aRectFnSet.GetRight(aTmp);
1243 // optimization:
1244 // Record in nNextTop at which Y-position frame related changes are
1245 // likely. This is so that, despite only looking at frames in the
1246 // current line height, for frames without wrap the line height is
1247 // incremented so that with a single line the lower border of the frame
1248 // (or possibly the upper border of another frame) is reached.
1249 // Especially in HTML documents there are often (dummy) paragraphs in
1250 // 2 pt font, and they used to only evade big frames after huge numbers
1251 // of empty lines.
1252 const tools::Long nTmpTop = aRectFnSet.GetTop(aTmp);
1253 if( aRectFnSet.YDiff( nTmpTop, aRectFnSet.GetTop(aLine) ) > 0 )
1255 if( aRectFnSet.YDiff( m_nNextTop, nTmpTop ) > 0 )
1256 SetNextTop( nTmpTop ); // upper border of next frame
1258 else if (!aRectFnSet.GetWidth(aTmp)) // typical for Objects with contour wrap
1259 { // For Objects with contour wrap that start before the current
1260 // line, and end below it, but do not actually overlap it, the
1261 // optimization has to be disabled, because the circumstances
1262 // can change in the next line.
1263 if( ! aRectFnSet.GetHeight(aTmp) ||
1264 aRectFnSet.YDiff( aRectFnSet.GetBottom(aTmp),
1265 aRectFnSet.GetTop(aLine) ) > 0 )
1266 SetNextTop( 0 );
1268 if( aTmp.Overlaps( aLine ) && nTmpRight > nFlyRight )
1270 nFlyRight = nTmpRight;
1271 if( css::text::WrapTextMode_RIGHT == eSurroundForTextWrap ||
1272 css::text::WrapTextMode_PARALLEL == eSurroundForTextWrap )
1274 // overrule the FlyFrame
1275 if( nRight > nFlyRight )
1276 nRight = nFlyRight;
1277 bStop = true;
1281 aRectFnSet.SetRight( rFly, nRight );
1284 // #i68520#
1285 void SwTextFly::CalcLeftMargin( SwRect &rFly,
1286 SwAnchoredObjList::size_type nFlyPos,
1287 const SwRect &rLine ) const
1289 OSL_ENSURE( !m_pCurrFrame->IsVertical() || !m_pCurrFrame->IsSwapped(),
1290 "SwTextFly::CalcLeftMargin with swapped frame" );
1291 SwRectFnSet aRectFnSet(m_pCurrFrame);
1292 // #118796# - correct determination of left of printing area
1293 SwTwips nLeft = aRectFnSet.GetPrtLeft(*m_pCurrFrame);
1294 const SwTwips nFlyLeft = aRectFnSet.GetLeft(rFly);
1296 if( nLeft > nFlyLeft )
1297 nLeft = rFly.Left();
1299 SwRect aLine( rLine );
1300 aRectFnSet.SetLeft( aLine, nLeft );
1302 // It is possible that there is another object that is _above_ us
1303 // and protrudes into the same line.
1304 // Flys with run-through are invisible for those below, i.e., they
1305 // are ignored for computing the margins of other Flys.
1306 // 3301: pNext->getFrameArea().Overlaps( rLine ) is necessary
1308 // #i68520#
1309 SwAnchoredObjList::size_type nMyPos = nFlyPos;
1310 while( ++nFlyPos < mpAnchoredObjList->size() )
1312 // #i68520#
1313 const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1314 const SwRect& aTmp( pNext->GetObjRectWithSpaces() );
1315 if( aRectFnSet.GetLeft(aTmp) >= nFlyLeft )
1316 break;
1319 while( nFlyPos )
1321 if( --nFlyPos == nMyPos )
1322 continue;
1323 // #i68520#
1324 const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1325 if( pNext == mpCurrAnchoredObj )
1326 continue;
1327 css::text::WrapTextMode eSurroundForTextWrap = GetSurroundForTextWrap( pNext );
1328 if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap )
1329 continue;
1331 const SwRect aTmp( SwContourCache::CalcBoundRect
1332 (pNext, aLine, m_pCurrFrame, nFlyLeft, false) );
1334 if( aRectFnSet.GetLeft(aTmp) < nFlyLeft && aTmp.Overlaps( aLine ) )
1336 // #118796# - no '+1', because <..fnGetRight>
1337 // returns the correct value.
1338 SwTwips nTmpRight = aRectFnSet.GetRight(aTmp);
1339 if ( nLeft <= nTmpRight )
1340 nLeft = nTmpRight;
1342 break;
1345 aRectFnSet.SetLeft( rFly, nLeft );
1348 // #i68520#
1349 SwRect SwTextFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
1350 const SwRect &rLine ) const
1352 SwRectFnSet aRectFnSet(m_pCurrFrame);
1354 const tools::Long nXPos = m_pCurrFrame->IsRightToLeft() ?
1355 rLine.Right() :
1356 aRectFnSet.GetLeft(rLine);
1358 SwRect aFly = mbIgnoreContour ?
1359 pAnchoredObj->GetObjRectWithSpaces() :
1360 SwContourCache::CalcBoundRect(pAnchoredObj, rLine, m_pCurrFrame,
1361 nXPos, !m_pCurrFrame->IsRightToLeft());
1363 if( !aFly.Width() )
1364 return aFly;
1366 // so the line may grow up to the lower edge of the frame
1367 SetNextTop( aRectFnSet.GetBottom(aFly) );
1368 SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );
1370 // LEFT and RIGHT, we grow the rectangle.
1371 // We have some problems, when several frames are to be seen.
1372 // At the moment, only the easier case is assumed:
1373 // + LEFT means that the text must flow on the left of the frame,
1374 // that is the frame expands to the right edge of the print area
1375 // or to the next frame.
1376 // + RIGHT is the opposite.
1377 // Otherwise the set distance between text and frame is always
1378 // added up.
1379 switch( GetSurroundForTextWrap( pAnchoredObj ) )
1381 case css::text::WrapTextMode_LEFT :
1383 CalcRightMargin( aFly, nFlyPos, rLine );
1384 break;
1386 case css::text::WrapTextMode_RIGHT :
1388 CalcLeftMargin( aFly, nFlyPos, rLine );
1389 break;
1391 case css::text::WrapTextMode_NONE :
1393 CalcRightMargin( aFly, nFlyPos, rLine );
1394 CalcLeftMargin( aFly, nFlyPos, rLine );
1395 break;
1397 default:
1398 break;
1400 return aFly;
1403 // #i68520#
1405 // Wrap only on sides with at least 2cm space for the text
1406 #define TEXT_MIN 1134
1408 // Wrap on both sides up to a frame width of 1.5cm
1409 #define FRAME_MAX 850
1411 css::text::WrapTextMode SwTextFly::GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
1413 const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
1414 const SwFormatSurround &rFlyFormat = pFormat->GetSurround();
1415 css::text::WrapTextMode eSurroundForTextWrap = rFlyFormat.GetSurround();
1417 if( rFlyFormat.IsAnchorOnly() && pAnchoredObj->GetAnchorFrame() != GetMaster() )
1419 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1420 if ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
1421 (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()))
1423 return css::text::WrapTextMode_NONE;
1427 // in cause of run-through and nowrap ignore smartly
1428 if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap ||
1429 css::text::WrapTextMode_NONE == eSurroundForTextWrap )
1430 return eSurroundForTextWrap;
1432 // left is left and right is right
1433 if (m_pCurrFrame->IsRightToLeft())
1435 if ( css::text::WrapTextMode_LEFT == eSurroundForTextWrap )
1436 eSurroundForTextWrap = css::text::WrapTextMode_RIGHT;
1437 else if ( css::text::WrapTextMode_RIGHT == eSurroundForTextWrap )
1438 eSurroundForTextWrap = css::text::WrapTextMode_LEFT;
1441 // "ideal page wrap":
1442 if ( css::text::WrapTextMode_DYNAMIC == eSurroundForTextWrap )
1444 SwRectFnSet aRectFnSet(m_pCurrFrame);
1445 const tools::Long nCurrLeft = aRectFnSet.GetPrtLeft(*m_pCurrFrame);
1446 const tools::Long nCurrRight = aRectFnSet.GetPrtRight(*m_pCurrFrame);
1447 const SwRect& aRect( pAnchoredObj->GetObjRectWithSpaces() );
1448 tools::Long nFlyLeft = aRectFnSet.GetLeft(aRect);
1449 tools::Long nFlyRight = aRectFnSet.GetRight(aRect);
1451 if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
1452 eSurroundForTextWrap = css::text::WrapTextMode_PARALLEL;
1453 else
1455 tools::Long nLeft = nFlyLeft - nCurrLeft;
1456 tools::Long nRight = nCurrRight - nFlyRight;
1457 if( nFlyRight - nFlyLeft > FRAME_MAX )
1459 if( nLeft < nRight )
1460 nLeft = 0;
1461 else
1462 nRight = 0;
1464 const int textMin = GetMaster()->GetDoc()
1465 .getIDocumentSettingAccess().get(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL )
1466 ? TEXT_MIN_SMALL : TEXT_MIN;
1468 // In case there is no space on either side, then css::text::WrapTextMode_PARALLEL
1469 // gives the same result when doing the initial layout or a layout
1470 // update after editing, so prefer that over css::text::WrapTextMode_NONE.
1471 if (nLeft == 0 && nRight == 0)
1472 return css::text::WrapTextMode_PARALLEL;
1474 if( nLeft < textMin )
1475 nLeft = 0;
1476 if( nRight < textMin )
1477 nRight = 0;
1478 if( nLeft )
1479 eSurroundForTextWrap = nRight ? css::text::WrapTextMode_PARALLEL : css::text::WrapTextMode_LEFT;
1480 else
1481 eSurroundForTextWrap = nRight ? css::text::WrapTextMode_RIGHT: css::text::WrapTextMode_NONE;
1485 return eSurroundForTextWrap;
1488 bool SwTextFly::IsAnyFrame( const SwRect &rLine ) const
1491 SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));
1493 OSL_ENSURE( m_bOn, "IsAnyFrame: Why?" );
1495 return ForEach( rLine, nullptr, false );
1498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */