1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
26 #include <swregion.hxx>
27 #include <dflyobj.hxx>
28 #include <drawfont.hxx>
30 #include <flyfrms.hxx>
31 #include <fmtornt.hxx>
33 #include <frmtool.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>
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>
61 using namespace ::com::sun::star
;
66 struct AnchoredObjOrder
71 AnchoredObjOrder( const bool bR2L
,
77 bool operator()( const SwAnchoredObject
* pListedAnchoredObj
,
78 const SwAnchoredObject
* pNewAnchoredObj
)
80 const SwRect
& aBoundRectOfListedObj( pListedAnchoredObj
->GetObjRectWithSpaces() );
81 const SwRect
& aBoundRectOfNewObj( pNewAnchoredObj
->GetObjRectWithSpaces() );
83 ( (aBoundRectOfListedObj
.*mfnRect
->fnGetRight
)() ==
84 (aBoundRectOfNewObj
.*mfnRect
->fnGetRight
)() ) ) ||
86 ( (aBoundRectOfListedObj
.*mfnRect
->fnGetLeft
)() ==
87 (aBoundRectOfNewObj
.*mfnRect
->fnGetLeft
)() ) ) )
90 (*mfnRect
->fnYDiff
)( (aBoundRectOfNewObj
.*mfnRect
->fnGetTop
)(),
91 (aBoundRectOfListedObj
.*mfnRect
->fnGetTop
)() );
94 ( (aBoundRectOfNewObj
.*mfnRect
->fnGetLeft
)() >
95 (aBoundRectOfListedObj
.*mfnRect
->fnGetLeft
)() ) ) ||
97 ( (aBoundRectOfNewObj
.*mfnRect
->fnGetRight
)() <
98 (aBoundRectOfListedObj
.*mfnRect
->fnGetRight
)() ) ) ) )
102 else if ( nTopDiff
> 0 )
108 ( (aBoundRectOfListedObj
.*mfnRect
->fnGetRight
)() >
109 (aBoundRectOfNewObj
.*mfnRect
->fnGetRight
)() ) ) ||
111 ( (aBoundRectOfListedObj
.*mfnRect
->fnGetLeft
)() <
112 (aBoundRectOfNewObj
.*mfnRect
->fnGetLeft
)() ) ) )
122 SwContourCache::SwContourCache() :
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
);
148 void ClrContourCache()
152 pContourCache
->mvItems
.clear();
153 pContourCache
->mnPointCount
= 0;
158 SwRect
SwContourCache::CalcBoundRect( const SwAnchoredObject
* pAnchoredObj
,
160 const SwTextFrame
* pFrame
,
161 const tools::Long nXPos
,
165 const SwFrameFormat
* pFormat
= &(pAnchoredObj
->GetFrameFormat());
166 bool bHandleContour(pFormat
->GetSurround().IsContour());
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
) )
190 pContourCache
= new SwContourCache
;
192 aRet
= pContourCache
->ContourRect(
193 pFormat
, pAnchoredObj
->GetDrawObj(), pFrame
, rLine
, nXPos
, bRight
);
200 aRet
= pAnchoredObj
->GetObjRectWithSpaces();
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
)
211 sal_uInt16 nPos
= 0; // Search in the Cache
212 while( nPos
< GetCount() && pObj
!= mvItems
[ nPos
].mpSdrObj
)
214 if( GetCount() == nPos
) // Not found
216 if( GetCount() == POLY_CNT
)
218 mnPointCount
-= mvItems
.back().mxTextRanger
->GetPointCount();
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());
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();
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();
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();
284 while( nIdx
< nCount
&& (*pTmp
)[ nIdx
] < nXPos
)
286 bool bOdd
= nIdx
% 2;
289 --nIdx
; // within interval
290 else if( ! bRight
&& ( nIdx
>= nCount
|| (*pTmp
)[ nIdx
] != nXPos
) )
293 nIdx
-= 2; // an interval to the left
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 );
309 SwTextFly::SwTextFly()
311 , mpCurrAnchoredObj(nullptr)
312 , m_pCurrFrame(nullptr)
316 , m_nCurrFrameNodeIndex(0)
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();
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;
376 m_nCurrFrameNodeIndex
= NODE_OFFSET_MAX
;
379 SwRect
SwTextFly::GetFrame_( const SwRect
&rRect
) const
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
);
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();
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() );
436 if( pObj
->GetObjRect().Left() > aRect
.Right() )
440 if( mpCurrAnchoredObj
!= pObj
&& aBound
.Overlaps( aRect
) )
447 const SwTextFrame
* SwTextFly::GetMaster_()
449 m_pMaster
= m_pCurrFrame
;
450 while (m_pMaster
&& m_pMaster
->IsFollow())
451 m_pMaster
= m_pMaster
->FindMaster();
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())
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
)])
474 aRect
.Width( aRect
.Width() + nSpaceCnt
* rInf
.GetSpace() );
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;
490 const sal_uInt32 nCurrOrd
= mpCurrAnchoredObj
491 ? mpCurrAnchoredObj
->GetDrawObj()->GetOrdNum()
493 OSL_ENSURE( !m_bTopRule
, "DrawTextOpaque: Wrong TopRule" );
496 const SwAnchoredObjList::size_type
nCount( m_bOn
? GetAnchoredObjList()->size() : 0 );
499 const SdrLayerID nHellId
= m_pPage
->getRootFrame()->GetCurrShell()->getIDocumentDrawModelAccess().GetHellId();
500 for( SwAnchoredObjList::size_type i
= 0; i
< nCount
; ++i
)
503 const SwAnchoredObject
* pTmpAnchoredObj
= (*mpAnchoredObjList
)[i
];
504 const SwFlyFrame
* pFly
= pTmpAnchoredObj
->DynCastFlyFrame();
505 if( pFly
&& mpCurrAnchoredObj
!= pTmpAnchoredObj
)
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() ||
518 GetMaster() == pFly
->GetAnchorFrame() ||
519 ((RndStdIds::FLY_AT_PARA
!= rAnchor
.GetAnchorId()) &&
520 (RndStdIds::FLY_AT_CHAR
!= rAnchor
.GetAnchorId())
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())
534 (!pNoText
->IsTransparent() && !rSur
.IsContour()) )
537 aRegion
-= pFly
->getFrameArea();
545 Point
aPos( rInf
.GetPos().X(), rInf
.GetPos().Y() + rInf
.GetAscent() );
546 const Point
aOldPos(rInf
.GetPos());
552 rInf
.GetFont()->DrawStretchText_( rInf
);
554 rInf
.GetFont()->DrawText_( rInf
);
555 rInf
.SetPos(aOldPos
);
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
);
568 rInf
.GetFont()->DrawStretchText_( rInf
);
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" );
581 const SwAnchoredObjList::size_type
nCount( m_bOn
? GetAnchoredObjList()->size() : 0 );
584 const SdrLayerID nHellId
= m_pPage
->getRootFrame()->GetCurrShell()->getIDocumentDrawModelAccess().GetHellId();
585 for( SwAnchoredObjList::size_type i
= 0; i
< nCount
; ++i
)
588 const SwAnchoredObject
* pAnchoredObjTmp
= (*mpAnchoredObjList
)[i
];
589 if (mpCurrAnchoredObj
== pAnchoredObjTmp
)
593 const SwFlyFrame
* pFly
= pAnchoredObjTmp
->DynCastFlyFrame();
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
605 ( ( css::text::WrapTextMode_THROUGH
== rSur
.GetSurround() )
607 ? (pAnchoredObjTmp
->GetDrawObj()->GetLayer() != nHellId
)
608 : !rSur
.IsContour() ) &&
609 !pFly
->IsBackgroundTransparent() &&
611 !pFly
->Lower()->IsNoTextFrame() ||
612 !static_cast<const SwNoTextFrame
*>(pFly
->Lower())->IsTransparent() );
616 SwRect
aFly( pAnchoredObjTmp
->GetObjRect() );
617 // OD 24.01.2003 #106593#
618 ::SwAlignRect( aFly
, m_pPage
->getRootFrame()->GetCurrShell(), pOut
);
619 if( !aFly
.IsEmpty() )
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
)
641 // <mpCurrAnchoredObj> is set, if <m_pCurrFrame> is inside a fly frame
642 if( _pAnchoredObj
!= mpCurrAnchoredObj
)
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))
655 if( ( bInFootnote
|| bInFooterOrHeader
) && m_bTopRule
)
658 const SwFrameFormat
& rFrameFormat
= _pAnchoredObj
->GetFrameFormat();
659 const SwFormatAnchor
& rNewA
= rFrameFormat
.GetAnchor();
660 if (RndStdIds::FLY_AT_PAGE
== rNewA
.GetAnchorId())
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
;
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())
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
711 // Within chained Flys we only avoid Lower
713 const SwFormatChain
&rChain
= mpCurrAnchoredObj
->GetFrameFormat().GetChain();
714 if ( !rChain
.GetPrev() && !rChain
.GetNext() )
717 const SwFormatAnchor
& rNewA
= _pAnchoredObj
->GetFrameFormat().GetAnchor();
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())
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
730 if (RndStdIds::FLY_AT_PAGE
== rNewA
.GetAnchorId())
732 if (RndStdIds::FLY_AT_PAGE
== rCurrA
.GetAnchorId())
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
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.
756 // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
758 bEvade
&= ( mpCurrAnchoredObj
->GetDrawObj()->GetOrdNum() < pNew
->GetOrdNum() );
762 const SwRect
& aTmp( _pAnchoredObj
->GetObjRectWithSpaces() );
763 if ( !aTmp
.Overlaps( mpCurrAnchoredObj
->GetObjRectWithSpaces() ) )
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?
783 const SwFrame
* pTmp
= _pAnchoredObj
->GetAnchorFrame();
784 if (pTmp
== m_pCurrFrame
)
786 if( pTmp
->IsTextFrame() && ( pTmp
->IsInFly() || pTmp
->IsInFootnote() ) )
789 Point aPos
= _pAnchoredObj
->GetObjRect().Pos();
790 pTmp
= GetVirtualUpper( pTmp
, aPos
);
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
))
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() )
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
)
849 SwRect
SwTextFly::GetFrameArea() const
851 // i#28701 - consider complete frame area for new text wrapping
853 if (m_pCurrFrame
->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING
))
855 aRect
= m_pCurrFrame
->getFramePrintArea();
856 aRect
+= m_pCurrFrame
->getFrameArea().Pos();
860 aRect
= m_pCurrFrame
->getFrameArea();
866 SwAnchoredObjList
* SwTextFly::InitAnchoredObjList()
868 OSL_ENSURE( m_pCurrFrame
, "InitFlyList: No Frame, no FlyList" );
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
) ||
886 (!m_pCurrFrame
->IsInFootnote() && !bFooterHeader
));
890 if( nCount
&& bWrapAllowed
)
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
)
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() )
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()) )
939 // #i26945# - pass <pAnchoredObj> to method
940 // <GetTop(..)> instead of only the <SdrObject> instance of the
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
951 SwAnchoredObjList::iterator aInsPosIter
=
952 std::lower_bound( mpAnchoredObjList
->begin(),
953 mpAnchoredObjList
->end(),
955 AnchoredObjOrder( bR2L
, aRectFnSet
.FnRect() ) );
957 mpAnchoredObjList
->insert( aInsPosIter
, pAnchoredObj
);
960 const SwFormatSurround
&rFlyFormat
= pAnchoredObj
->GetFrameFormat().GetSurround();
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
) );
978 SwTwips nMax
= aRectFnSet
.GetPrtBottom(*m_pCurrFrame
->GetUpper());
979 if( aRectFnSet
.YDiff( m_nMinBottom
, nMax
) > 0 )
986 mpAnchoredObjList
.reset( new SwAnchoredObjList
);
990 return mpAnchoredObjList
.get();
993 SwTwips
SwTextFly::CalcMinBottom() const
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;
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();
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.
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.
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.
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.
1076 SwTwips nBottom
= aRect
.Top() + aRect
.Height();
1085 bool SwTextFly::ForEach( const SwRect
&rRect
, SwRect
* pRect
, bool bAvoid
) const
1087 SwSwapIfSwapped
swap(const_cast<SwTextFrame
*>(m_pCurrFrame
));
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)
1101 ( !pPageDesc
->GetFollow() || pPageDesc
->GetFollow() == pPageDesc
) )
1109 const SwAnchoredObjList::size_type
nCount( m_bOn
? GetAnchoredObjList()->size() : 0 );
1112 for( SwAnchoredObjList::size_type i
= 0; i
< nCount
; ++i
)
1115 const SwAnchoredObject
* pAnchoredObj
= (*mpAnchoredObjList
)[i
];
1117 SwRect
aRect( pAnchoredObj
->GetObjRectWithSpaces() );
1119 if( aRectFnSet
.GetLeft(aRect
) > aRectFnSet
.GetRight(rRect
) )
1123 if ( mpCurrAnchoredObj
!= pAnchoredObj
&& aRect
.Overlaps( rRect
) )
1126 const SwFormat
* pFormat( &(pAnchoredObj
->GetFrameFormat()) );
1127 const SwFormatSurround
&rSur
= pFormat
->GetSurround();
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() ||
1137 GetMaster() == pAnchoredObj
->GetAnchorFrame() ||
1138 ((RndStdIds::FLY_AT_PARA
!= rAnchor
.GetAnchorId()) &&
1139 (RndStdIds::FLY_AT_CHAR
!= rAnchor
.GetAnchorId())) ) )
1140 || aRect
.Top() == FAR_AWAY
)
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.
1152 if ( mbIgnoreCurrentFrame
&&
1153 GetMaster() == pAnchoredObj
->GetAnchorFrame() )
1159 SwRect aFly
= AnchoredObjToRect( pAnchoredObj
, rRect
);
1160 if( aFly
.IsEmpty() || !aFly
.Overlaps( rRect
) )
1163 (!m_pCurrFrame
->IsRightToLeft() &&
1164 ( aRectFnSet
.GetLeft(aFly
) <
1165 aRectFnSet
.GetLeft(*pRect
) ) ) ||
1166 (m_pCurrFrame
->IsRightToLeft() &&
1167 ( aRectFnSet
.GetRight(aFly
) >
1168 aRectFnSet
.GetRight(*pRect
) ) ) ) )
1170 if( rSur
.IsContour() )
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
] )
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
1217 css::text::WrapTextMode eSurroundForTextWrap
;
1221 SwAnchoredObjList::size_type nPos
= 0;
1224 while( nPos
< mpAnchoredObjList
->size() && !bStop
)
1226 if( nPos
== nFlyPos
)
1232 const SwAnchoredObject
* pNext
= (*mpAnchoredObjList
)[ nPos
++ ];
1233 if ( pNext
== mpCurrAnchoredObj
)
1235 eSurroundForTextWrap
= GetSurroundForTextWrap( pNext
);
1236 if( css::text::WrapTextMode_THROUGH
== eSurroundForTextWrap
)
1239 const SwRect
aTmp( SwContourCache::CalcBoundRect
1240 ( pNext
, aLine
, m_pCurrFrame
, nFlyRight
, true ) );
1241 SwTwips nTmpRight
= aRectFnSet
.GetRight(aTmp
);
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
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 )
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
)
1281 aRectFnSet
.SetRight( rFly
, nRight
);
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
1309 SwAnchoredObjList::size_type nMyPos
= nFlyPos
;
1310 while( ++nFlyPos
< mpAnchoredObjList
->size() )
1313 const SwAnchoredObject
* pNext
= (*mpAnchoredObjList
)[ nFlyPos
];
1314 const SwRect
& aTmp( pNext
->GetObjRectWithSpaces() );
1315 if( aRectFnSet
.GetLeft(aTmp
) >= nFlyLeft
)
1321 if( --nFlyPos
== nMyPos
)
1324 const SwAnchoredObject
* pNext
= (*mpAnchoredObjList
)[ nFlyPos
];
1325 if( pNext
== mpCurrAnchoredObj
)
1327 css::text::WrapTextMode eSurroundForTextWrap
= GetSurroundForTextWrap( pNext
);
1328 if( css::text::WrapTextMode_THROUGH
== eSurroundForTextWrap
)
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
)
1345 aRectFnSet
.SetLeft( rFly
, nLeft
);
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() ?
1356 aRectFnSet
.GetLeft(rLine
);
1358 SwRect aFly
= mbIgnoreContour
?
1359 pAnchoredObj
->GetObjRectWithSpaces() :
1360 SwContourCache::CalcBoundRect(pAnchoredObj
, rLine
, m_pCurrFrame
,
1361 nXPos
, !m_pCurrFrame
->IsRightToLeft());
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
1379 switch( GetSurroundForTextWrap( pAnchoredObj
) )
1381 case css::text::WrapTextMode_LEFT
:
1383 CalcRightMargin( aFly
, nFlyPos
, rLine
);
1386 case css::text::WrapTextMode_RIGHT
:
1388 CalcLeftMargin( aFly
, nFlyPos
, rLine
);
1391 case css::text::WrapTextMode_NONE
:
1393 CalcRightMargin( aFly
, nFlyPos
, rLine
);
1394 CalcLeftMargin( aFly
, nFlyPos
, rLine
);
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
;
1455 tools::Long nLeft
= nFlyLeft
- nCurrLeft
;
1456 tools::Long nRight
= nCurrRight
- nFlyRight
;
1457 if( nFlyRight
- nFlyLeft
> FRAME_MAX
)
1459 if( nLeft
< nRight
)
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
)
1476 if( nRight
< textMin
)
1479 eSurroundForTextWrap
= nRight
? css::text::WrapTextMode_PARALLEL
: css::text::WrapTextMode_LEFT
;
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: */