Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <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 "frmtool.hxx"
31 : #include "porfly.hxx"
32 : #include "porfld.hxx"
33 : #include "txtfly.hxx"
34 : #include "txtpaint.hxx"
35 : #include "txtatr.hxx"
36 : #include "notxtfrm.hxx"
37 : #include "fmtcnct.hxx"
38 : #include "inftxt.hxx"
39 : #include <pormulti.hxx>
40 : #include <svx/obj3d.hxx>
41 : #include <editeng/txtrange.hxx>
42 : #include <editeng/lrspitem.hxx>
43 : #include <editeng/ulspitem.hxx>
44 : #include <editeng/lspcitem.hxx>
45 : #include <fmtsrnd.hxx>
46 : #include <fmtanchr.hxx>
47 : #include <frmfmt.hxx>
48 : #include <pagedesc.hxx>
49 : #include <tgrditem.hxx>
50 : #include <sortedobjs.hxx>
51 : #include <layouter.hxx>
52 : #include <IDocumentDrawModelAccess.hxx>
53 : #include <IDocumentLayoutAccess.hxx>
54 : #include <IDocumentSettingAccess.hxx>
55 : #include <svx/svdoedge.hxx>
56 :
57 : #ifdef DBG_UTIL
58 : #include "viewsh.hxx"
59 : #include "viewopt.hxx"
60 : #include "doc.hxx"
61 : #endif
62 :
63 : using namespace ::com::sun::star;
64 :
65 : namespace
66 : {
67 : // #i68520#
68 : struct AnchoredObjOrder
69 : {
70 : bool mbR2L;
71 : SwRectFn mfnRect;
72 :
73 109675 : AnchoredObjOrder( const bool bR2L,
74 : SwRectFn fnRect )
75 : : mbR2L( bR2L ),
76 109675 : mfnRect( fnRect )
77 109675 : {}
78 :
79 510300 : bool operator()( const SwAnchoredObject* pListedAnchoredObj,
80 : const SwAnchoredObject* pNewAnchoredObj )
81 : {
82 510300 : const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
83 510300 : const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
84 510300 : if ( ( mbR2L &&
85 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
86 1024623 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
87 1020600 : ( !mbR2L &&
88 510300 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
89 510300 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
90 : {
91 : SwTwips nTopDiff =
92 4023 : (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
93 8046 : (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
94 4023 : if ( nTopDiff == 0 &&
95 0 : ( ( mbR2L &&
96 0 : ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
97 35 : (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
98 70 : ( !mbR2L &&
99 35 : ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
100 35 : (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
101 : {
102 0 : return true;
103 : }
104 4023 : else if ( nTopDiff > 0 )
105 : {
106 2326 : return true;
107 : }
108 : }
109 506277 : else if ( ( mbR2L &&
110 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
111 1242360 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
112 1012554 : ( !mbR2L &&
113 506277 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
114 506277 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
115 : {
116 229806 : return true;
117 : }
118 :
119 278168 : return false;
120 : }
121 : };
122 : }
123 :
124 3 : SwContourCache::SwContourCache() :
125 3 : nPntCnt( 0 ), nObjCnt( 0 )
126 : {
127 3 : memset( pSdrObj, 0, sizeof(pSdrObj) );
128 3 : memset( pTextRanger, 0, sizeof(pTextRanger) );
129 3 : }
130 :
131 3 : SwContourCache::~SwContourCache()
132 : {
133 3 : for( sal_uInt16 i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
134 : ;
135 3 : }
136 :
137 9 : void SwContourCache::ClrObject( sal_uInt16 nPos )
138 : {
139 : assert(pTextRanger[nPos] && "ClrObject: Already cleared. Good Bye!");
140 9 : nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
141 9 : delete pTextRanger[ nPos ];
142 9 : --nObjCnt;
143 9 : memmove( const_cast<SdrObject**>(pSdrObj) + nPos, pSdrObj + nPos + 1,
144 18 : ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
145 9 : memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
146 18 : ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
147 9 : }
148 :
149 5240 : void ClrContourCache( const SdrObject *pObj )
150 : {
151 5240 : if( pContourCache && pObj )
152 231 : for( sal_uInt16 i = 0; i < pContourCache->GetCount(); ++i )
153 10 : if( pObj == pContourCache->GetObject( i ) )
154 : {
155 9 : pContourCache->ClrObject( i );
156 9 : break;
157 : }
158 5240 : }
159 :
160 2979 : void ClrContourCache()
161 : {
162 2979 : if( pContourCache )
163 : {
164 434 : for( sal_uInt16 i = 0; i < pContourCache->GetCount();
165 12 : delete pContourCache->pTextRanger[ i++ ] )
166 : ;
167 211 : pContourCache->nObjCnt = 0;
168 211 : pContourCache->nPntCnt = 0;
169 : }
170 2979 : }
171 :
172 : // #i68520#
173 2949 : const SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
174 : const SwRect &rLine,
175 : const SwTextFrm* pFrm,
176 : const long nXPos,
177 : const bool bRight )
178 : {
179 2949 : SwRect aRet;
180 2949 : const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
181 4081 : if( pFormat->GetSurround().IsContour() &&
182 674 : ( !pAnchoredObj->ISA(SwFlyFrm) ||
183 216 : ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
184 108 : static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTextFrm() ) ) )
185 : {
186 566 : aRet = pAnchoredObj->GetObjRectWithSpaces();
187 566 : if( aRet.IsOver( rLine ) )
188 : {
189 566 : if( !pContourCache )
190 3 : pContourCache = new SwContourCache;
191 :
192 1132 : aRet = pContourCache->ContourRect(
193 566 : pFormat, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
194 : }
195 : else
196 0 : aRet.Width( 0 );
197 : }
198 : else
199 : {
200 2383 : aRet = pAnchoredObj->GetObjRectWithSpaces();
201 : }
202 :
203 2949 : return aRet;
204 : }
205 :
206 566 : const SwRect SwContourCache::ContourRect( const SwFormat* pFormat,
207 : const SdrObject* pObj, const SwTextFrm* pFrm, const SwRect &rLine,
208 : const long nXPos, const bool bRight )
209 : {
210 566 : SwRect aRet;
211 566 : sal_uInt16 nPos = 0; // Search in the Cache
212 1359 : while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
213 227 : ++nPos;
214 566 : if( GetCount() == nPos ) // Not found
215 : {
216 15 : if( nObjCnt == POLY_CNT )
217 : {
218 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
219 0 : delete pTextRanger[ nObjCnt ];
220 : }
221 15 : ::basegfx::B2DPolyPolygon aPolyPolygon;
222 15 : ::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;
223 :
224 15 : if ( pObj->ISA(SwVirtFlyDrawObj) )
225 : {
226 : // GetContour() causes the graphic to be loaded, which may cause
227 : // the graphic to change its size, call ClrObject()
228 6 : tools::PolyPolygon aPoly;
229 6 : if( !static_cast<const SwVirtFlyDrawObj*>(pObj)->GetFlyFrm()->GetContour( aPoly ) )
230 0 : aPoly = tools::PolyPolygon( static_cast<const SwVirtFlyDrawObj*>(pObj)->
231 0 : GetFlyFrm()->Frm().SVRect() );
232 6 : aPolyPolygon.clear();
233 6 : aPolyPolygon.append(aPoly.getB2DPolyPolygon());
234 : }
235 : else
236 : {
237 9 : if( !pObj->ISA( E3dObject ) )
238 : {
239 9 : aPolyPolygon = pObj->TakeXorPoly();
240 : }
241 :
242 9 : ::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour());
243 9 : pPolyPolygon = new ::basegfx::B2DPolyPolygon(aContourPoly);
244 : }
245 15 : const SvxLRSpaceItem &rLRSpace = pFormat->GetLRSpace();
246 15 : const SvxULSpaceItem &rULSpace = pFormat->GetULSpace();
247 15 : memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
248 15 : memmove( const_cast<SdrObject**>(pSdrObj) + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
249 15 : pSdrObj[ 0 ] = pObj; // due to #37347 the Object must be entered only
250 : // after GetContour()
251 : pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
252 30 : (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(),
253 30 : pFormat->GetSurround().IsOutside(), false, pFrm->IsVertical() );
254 15 : pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
255 15 : pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );
256 :
257 15 : delete pPolyPolygon;
258 :
259 15 : nPntCnt += pTextRanger[ 0 ]->GetPointCount();
260 30 : while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
261 : {
262 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
263 0 : delete pTextRanger[ nObjCnt ];
264 15 : }
265 : }
266 551 : else if( nPos )
267 : {
268 224 : const SdrObject* pTmpObj = pSdrObj[ nPos ];
269 224 : TextRanger* pTmpRanger = pTextRanger[ nPos ];
270 224 : memmove( const_cast<SdrObject**>(pSdrObj) + 1, pSdrObj, nPos * sizeof( SdrObject* ) );
271 224 : memmove( pTextRanger + 1, pTextRanger, nPos * sizeof( TextRanger* ) );
272 224 : pSdrObj[ 0 ] = pTmpObj;
273 224 : pTextRanger[ 0 ] = pTmpRanger;
274 : }
275 566 : SWRECTFN( pFrm )
276 566 : long nTmpTop = (rLine.*fnRect->fnGetTop)();
277 : // fnGetBottom is top + height
278 566 : long nTmpBottom = (rLine.*fnRect->fnGetBottom)();
279 :
280 566 : Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );
281 :
282 566 : LongDqPtr pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );
283 :
284 566 : const size_t nCount = pTmp->size();
285 566 : if( 0 != nCount )
286 : {
287 548 : size_t nIdx = 0;
288 1456 : while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
289 360 : ++nIdx;
290 548 : bool bOdd = (nIdx % 2);
291 548 : bool bSet = true;
292 548 : if( bOdd )
293 60 : --nIdx; // within interval
294 488 : else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
295 : {
296 0 : if( nIdx )
297 0 : nIdx -= 2; // an interval to the left
298 : else
299 0 : bSet = false; // before the first interval
300 : }
301 :
302 548 : if( bSet && nIdx < nCount )
303 : {
304 796 : (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
305 1194 : (rLine.*fnRect->fnGetHeight)() );
306 398 : (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
307 398 : (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
308 : }
309 : }
310 566 : return aRet;
311 : }
312 :
313 69633 : SwTextFly::SwTextFly()
314 : : pPage(0)
315 : , mpCurrAnchoredObj(0)
316 : , pCurrFrm(0)
317 : , pMaster(0)
318 : , mpAnchoredObjList(0)
319 : , nMinBottom(0)
320 : , nNextTop(0)
321 : , nIndex(0)
322 : , bOn(false)
323 : , bTopRule(false)
324 : , mbIgnoreCurrentFrame(false)
325 : , mbIgnoreContour(false)
326 69633 : , mbIgnoreObjsInHeaderFooter(false)
327 :
328 : {
329 69633 : }
330 :
331 91999 : SwTextFly::SwTextFly( const SwTextFrm *pFrm )
332 : {
333 91999 : CtorInitTextFly( pFrm );
334 91999 : }
335 :
336 57202 : SwTextFly::SwTextFly( const SwTextFly& rTextFly )
337 : {
338 57202 : pPage = rTextFly.pPage;
339 57202 : mpCurrAnchoredObj = rTextFly.mpCurrAnchoredObj;
340 57202 : pCurrFrm = rTextFly.pCurrFrm;
341 57202 : pMaster = rTextFly.pMaster;
342 57202 : if( rTextFly.mpAnchoredObjList )
343 : {
344 25672 : mpAnchoredObjList = new SwAnchoredObjList( *(rTextFly.mpAnchoredObjList) );
345 : }
346 : else
347 : {
348 31530 : mpAnchoredObjList = NULL;
349 : }
350 :
351 57202 : bOn = rTextFly.bOn;
352 57202 : bTopRule = rTextFly.bTopRule;
353 57202 : nMinBottom = rTextFly.nMinBottom;
354 57202 : nNextTop = rTextFly.nNextTop;
355 57202 : nIndex = rTextFly.nIndex;
356 57202 : mbIgnoreCurrentFrame = rTextFly.mbIgnoreCurrentFrame;
357 57202 : mbIgnoreContour = rTextFly.mbIgnoreContour;
358 57202 : mbIgnoreObjsInHeaderFooter = rTextFly.mbIgnoreObjsInHeaderFooter;
359 57202 : }
360 :
361 218834 : SwTextFly::~SwTextFly()
362 : {
363 218834 : delete mpAnchoredObjList;
364 218834 : }
365 :
366 161632 : void SwTextFly::CtorInitTextFly( const SwTextFrm *pFrm )
367 : {
368 161632 : mbIgnoreCurrentFrame = false;
369 161632 : mbIgnoreContour = false;
370 : // #118809#
371 161632 : mbIgnoreObjsInHeaderFooter = false;
372 161632 : pPage = pFrm->FindPageFrm();
373 161632 : const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
374 : // #i68520#
375 161632 : mpCurrAnchoredObj = pTmp;
376 161632 : pCurrFrm = pFrm;
377 161632 : pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
378 : // #i68520#
379 161632 : mpAnchoredObjList = NULL;
380 : // If we're not overlapped by a frame or if a FlyCollection does not exist
381 : // at all, we switch off forever.
382 : // It could be, however, that a line is added while formatting, that
383 : // extends into a frame.
384 : // That's why we do not optimize for: bOn = pSortedFlys && IsAnyFrm();
385 161632 : bOn = pPage->GetSortedObjs() != 0;
386 161632 : bTopRule = true;
387 161632 : nMinBottom = 0;
388 161632 : nNextTop = 0;
389 161632 : nIndex = ULONG_MAX;
390 161632 : }
391 :
392 76680 : SwRect SwTextFly::_GetFrm( const SwRect &rRect, bool bTop ) const
393 : {
394 76680 : SwRect aRet;
395 76680 : if( ForEach( rRect, &aRet, true ) )
396 : {
397 2761 : SWRECTFN( pCurrFrm )
398 2761 : if( bTop )
399 2761 : (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );
400 :
401 : // Do not always adapt the bottom
402 2761 : const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
403 2761 : const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
404 3594 : if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
405 833 : (aRet.*fnRect->fnGetHeight)() < 0 )
406 1928 : (aRet.*fnRect->fnSetBottom)( nRectBottom );
407 : }
408 76680 : return aRet;
409 : }
410 :
411 5577 : bool SwTextFly::IsAnyFrm() const
412 : {
413 5577 : SWAP_IF_SWAPPED swap(const_cast<SwTextFrm *>(pCurrFrm));
414 :
415 : OSL_ENSURE( bOn, "IsAnyFrm: Why?" );
416 11154 : SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
417 11154 : pCurrFrm->Prt().SSize() );
418 :
419 5577 : return ForEach( aRect, NULL, false );
420 : }
421 :
422 7933 : bool SwTextFly::IsAnyObj( const SwRect &rRect ) const
423 : {
424 : OSL_ENSURE( bOn, "SwTextFly::IsAnyObj: Who's knocking?" );
425 :
426 7933 : SwRect aRect( rRect );
427 7933 : if ( aRect.IsEmpty() )
428 15866 : aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
429 15866 : pCurrFrm->Prt().SSize() );
430 :
431 7933 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
432 7933 : if( pSorted ) // bOn actually makes sure that we have objects on the side,
433 : // but who knows who deleted somehting in the meantime?
434 : {
435 19569 : for ( size_t i = 0; i < pSorted->size(); ++i )
436 : {
437 16471 : const SwAnchoredObject* pObj = (*pSorted)[i];
438 :
439 16471 : const SwRect aBound( pObj->GetObjRectWithSpaces() );
440 :
441 : // Optimization
442 16471 : if( pObj->GetObjRect().Left() > aRect.Right() )
443 3141 : continue;
444 :
445 : // #i68520#
446 13330 : if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
447 4835 : return true;
448 : }
449 : }
450 3098 : return false;
451 : }
452 :
453 1706 : const SwContentFrm* SwTextFly::_GetMaster()
454 : {
455 1706 : pMaster = pCurrFrm;
456 7079 : while( pMaster && pMaster->IsFollow() )
457 3667 : pMaster = static_cast<SwContentFrm*>(pMaster->FindMaster());
458 1706 : return pMaster;
459 : }
460 :
461 280 : bool SwTextFly::DrawTextOpaque( SwDrawTextInfo &rInf )
462 : {
463 280 : SwSaveClip aClipSave( rInf.GetpOut() );
464 280 : SwRect aRect( rInf.GetPos(), rInf.GetSize() );
465 280 : if( rInf.GetSpace() )
466 : {
467 10 : sal_Int32 nTmpLen = COMPLETE_STRING == rInf.GetLen() ? rInf.GetText().getLength() :
468 10 : rInf.GetLen();
469 10 : if( rInf.GetSpace() > 0 )
470 : {
471 10 : sal_Int32 nSpaceCnt = 0;
472 10 : const sal_Int32 nEndPos = rInf.GetIdx() + nTmpLen;
473 532 : for( sal_Int32 nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos )
474 : {
475 522 : if( CH_BLANK == rInf.GetText()[ nPos ] )
476 75 : ++nSpaceCnt;
477 : }
478 10 : if( nSpaceCnt )
479 8 : aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
480 : }
481 : else
482 0 : aRect.Width( aRect.Width() - nTmpLen * rInf.GetSpace() );
483 : }
484 :
485 280 : if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
486 : {
487 104 : SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
488 104 : aRect.Intersection( aClipRect );
489 : }
490 :
491 560 : SwRegionRects aRegion( aRect );
492 :
493 280 : bool bOpaque = false;
494 : // #i68520#
495 : const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
496 0 : ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
497 280 : : SAL_MAX_UINT32;
498 : OSL_ENSURE( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
499 :
500 : // #i68520#
501 280 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
502 280 : if ( bOn && nCount > 0 )
503 : {
504 280 : const sal_uInt16 nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
505 795 : for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
506 : {
507 : // #i68520#
508 515 : const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
509 821 : if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
510 1030 : mpCurrAnchoredObj != pTmpAnchoredObj )
511 : {
512 : // #i68520#
513 306 : const SwFlyFrm& rFly = dynamic_cast<const SwFlyFrm&>(*pTmpAnchoredObj);
514 306 : if( aRegion.GetOrigin().IsOver( rFly.Frm() ) )
515 : {
516 38 : const SwFrameFormat *pFormat = rFly.GetFormat();
517 38 : const SwFormatSurround &rSur = pFormat->GetSurround();
518 38 : const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
519 : // Only the ones who are opaque and more to the top
520 105 : if( ! rFly.IsBackgroundTransparent() &&
521 58 : SURROUND_THROUGHT == rSur.GetSurround() &&
522 29 : ( !rSur.IsAnchorOnly() ||
523 : // #i68520#
524 0 : GetMaster() == rFly.GetAnchorFrm() ||
525 0 : ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
526 0 : (FLY_AT_CHAR != rAnchor.GetAnchorId())
527 : )
528 29 : ) &&
529 : // #i68520#
530 79 : pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
531 12 : nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
532 : )
533 : {
534 : // Except for the content is transparent
535 : const SwNoTextFrm *pNoText =
536 0 : rFly.Lower() && rFly.Lower()->IsNoTextFrm()
537 0 : ? static_cast<const SwNoTextFrm*>(rFly.Lower())
538 0 : : 0;
539 0 : if ( !pNoText ||
540 0 : (!pNoText->IsTransparent() && !rSur.IsContour()) )
541 : {
542 0 : bOpaque = true;
543 0 : aRegion -= rFly.Frm();
544 : }
545 : }
546 : }
547 : }
548 : }
549 : }
550 :
551 280 : Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
552 280 : const Point aOldPos(rInf.GetPos());
553 280 : rInf.SetPos( aPos );
554 :
555 280 : if( !bOpaque )
556 : {
557 280 : if( rInf.GetKern() )
558 1 : rInf.GetFont()->_DrawStretchText( rInf );
559 : else
560 279 : rInf.GetFont()->_DrawText( rInf );
561 280 : rInf.SetPos(aOldPos);
562 280 : return false;
563 : }
564 0 : else if( !aRegion.empty() )
565 : {
566 : // What a huge effort ...
567 0 : SwSaveClip aClipVout( rInf.GetpOut() );
568 0 : for( size_t i = 0; i < aRegion.size(); ++i )
569 : {
570 0 : SwRect &rRect = aRegion[i];
571 0 : if( rRect != aRegion.GetOrigin() )
572 0 : aClipVout.ChgClip( rRect );
573 0 : if( rInf.GetKern() )
574 0 : rInf.GetFont()->_DrawStretchText( rInf );
575 : else
576 0 : rInf.GetFont()->_DrawText( rInf );
577 0 : }
578 : }
579 0 : rInf.SetPos(aOldPos);
580 280 : return true;
581 : }
582 :
583 30 : void SwTextFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
584 : const SwTextPaintInfo &rInf, bool bNoGraphic )
585 : {
586 30 : SwRegionRects aRegion( rRect );
587 : OSL_ENSURE( !bTopRule, "DrawFlyRect: Wrong TopRule" );
588 : // #i68520#
589 30 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
590 30 : if ( bOn && nCount > 0 )
591 : {
592 30 : const sal_uInt16 nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
593 77 : for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
594 : {
595 : // #i68520#
596 47 : const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
597 47 : if (mpCurrAnchoredObj == pAnchoredObjTmp)
598 0 : continue;
599 :
600 : // #i68520#
601 47 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
602 47 : if (pFly)
603 : {
604 : // #i68520#
605 47 : const SwFormatSurround& rSur = pAnchoredObjTmp->GetFrameFormat().GetSurround();
606 :
607 : // OD 24.01.2003 #106593# - correct clipping of fly frame area.
608 : // Consider that fly frame background/shadow can be transparent
609 : // and <SwAlignRect(..)> fly frame area
610 : // #i47804# - consider transparent graphics
611 : // and OLE objects.
612 : bool bClipFlyArea =
613 47 : ( ( SURROUND_THROUGHT == rSur.GetSurround() )
614 : // #i68520#
615 0 : ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
616 94 : : !rSur.IsContour() ) &&
617 188 : !pFly->IsBackgroundTransparent() &&
618 94 : ( !pFly->Lower() ||
619 47 : !pFly->Lower()->IsNoTextFrm() ||
620 47 : !static_cast<const SwNoTextFrm*>(pFly->Lower())->IsTransparent() );
621 47 : if ( bClipFlyArea )
622 : {
623 : // #i68520#
624 47 : SwRect aFly( pAnchoredObjTmp->GetObjRect() );
625 : // OD 24.01.2003 #106593#
626 47 : ::SwAlignRect( aFly, pPage->getRootFrm()->GetCurrShell() );
627 47 : if( aFly.Width() > 0 && aFly.Height() > 0 )
628 47 : aRegion -= aFly;
629 : }
630 : }
631 : }
632 : }
633 :
634 60 : for( size_t i = 0; i < aRegion.size(); ++i )
635 : {
636 30 : if ( bNoGraphic )
637 : {
638 30 : pOut->DrawRect( aRegion[i].SVRect() );
639 : }
640 : else
641 : {
642 0 : if(reinterpret_cast<SvxBrushItem*>(-1) != rInf.GetBrushItem())
643 : {
644 0 : ::DrawGraphic(rInf.GetBrushItem(), pOut, rInf.GetBrushRect(), aRegion[i] );
645 : }
646 : else
647 : {
648 : OSL_ENSURE(false, "DrawRect: Uninitialized BrushItem!" );
649 : }
650 : }
651 30 : }
652 30 : }
653 :
654 : /**
655 : * #i26945# - change first parameter
656 : * Now it's the <SwAnchoredObject> instance of the floating screen object
657 : */
658 140330 : bool SwTextFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
659 : const bool bInFootnote,
660 : const bool bInFooterOrHeader )
661 : {
662 : // #i68520#
663 : // <mpCurrAnchoredObj> is set, if <pCurrFrm> is inside a fly frame
664 140330 : if( _pAnchoredObj != mpCurrAnchoredObj )
665 : {
666 : // #i26945#
667 136710 : const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
668 : // #102344# Ignore connectors which have one or more connections
669 136710 : if(pNew && pNew->ISA(SdrEdgeObj))
670 : {
671 0 : if(static_cast<const SdrEdgeObj*>(pNew)->GetConnectedNode(true)
672 0 : || static_cast<const SdrEdgeObj*>(pNew)->GetConnectedNode(false))
673 : {
674 0 : return false;
675 : }
676 : }
677 :
678 136710 : if( ( bInFootnote || bInFooterOrHeader ) && bTopRule )
679 : {
680 : // #i26945#
681 0 : const SwFrameFormat& rFrameFormat = _pAnchoredObj->GetFrameFormat();
682 0 : const SwFormatAnchor& rNewA = rFrameFormat.GetAnchor();
683 0 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
684 : {
685 0 : if ( bInFootnote )
686 0 : return false;
687 :
688 0 : if ( bInFooterOrHeader )
689 : {
690 0 : SwFormatVertOrient aVert( rFrameFormat.GetVertOrient() );
691 0 : bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
692 0 : aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
693 0 : if( bVertPrt )
694 0 : return false;
695 : }
696 : }
697 : }
698 :
699 : // #i68520#
700 : // bEvade: consider pNew, if we are not inside a fly
701 : // consider pNew, if pNew is lower of <mpCurrAnchoredObj>
702 154222 : bool bEvade = !mpCurrAnchoredObj ||
703 154222 : Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);
704 :
705 136710 : if ( !bEvade )
706 : {
707 : // We are currently inside a fly frame and pNew is not
708 : // inside this fly frame. We can do some more checks if
709 : // we have to consider pNew.
710 :
711 : // If bTopRule is not set, we ignore the frame types.
712 : // We directly check the z-order
713 17321 : if ( !bTopRule )
714 1979 : bEvade = true;
715 : else
716 : {
717 : // Within chained Flys we only avoid Lower
718 : // #i68520#
719 15342 : const SwFormatChain &rChain = mpCurrAnchoredObj->GetFrameFormat().GetChain();
720 15342 : if ( !rChain.GetPrev() && !rChain.GetNext() )
721 : {
722 : // #i26945#
723 15046 : const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat().GetAnchor();
724 : // #i68520#
725 15046 : const SwFormatAnchor& rCurrA = mpCurrAnchoredObj->GetFrameFormat().GetAnchor();
726 :
727 : // If <mpCurrAnchoredObj> is anchored as character, its content
728 : // does not wrap around pNew
729 15046 : if (FLY_AS_CHAR == rCurrA.GetAnchorId())
730 89 : return false;
731 :
732 : // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
733 : // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
734 : // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
735 : // some more checks
736 14957 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
737 : {
738 21 : if (FLY_AT_PAGE == rCurrA.GetAnchorId())
739 : {
740 21 : bEvade = true;
741 : }
742 : else
743 0 : return false;
744 : }
745 14936 : else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
746 0 : return false; // Page anchored ones only avoid page anchored ones
747 14936 : else if (FLY_AT_FLY == rNewA.GetAnchorId())
748 0 : bEvade = true; // Non-page anchored ones avoid frame anchored ones
749 14936 : else if( FLY_AT_FLY == rCurrA.GetAnchorId() )
750 0 : return false; // Frame anchored ones do not avoid paragraph anchored ones
751 : // #i57062#
752 : // In order to avoid loop situation, it's decided to adjust
753 : // the wrapping behaviour of content of at-paragraph/at-character
754 : // anchored objects to one in the page header/footer and
755 : // the document body --> content of at-paragraph/at-character
756 : // anchored objects doesn't wrap around each other.
757 : else
758 14936 : return false;
759 : }
760 : }
761 :
762 : // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
763 : // #i68520#
764 2296 : bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
765 2296 : if( bEvade )
766 : {
767 : // #i68520#
768 416 : SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
769 416 : if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
770 357 : bEvade = false;
771 : }
772 : }
773 :
774 121685 : if ( bEvade )
775 : {
776 : // #i26945#
777 119448 : const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat().GetAnchor();
778 : OSL_ENSURE( FLY_AS_CHAR != rNewA.GetAnchorId(),
779 : "Don't call GetTop with a FlyInCntFrm" );
780 119448 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
781 904 : return true; // We always avoid page anchored ones
782 :
783 : // If Flys anchored at paragraph are caught in a FlyCnt, then
784 : // their influence ends at the borders of the FlyCnt!
785 : // If we are currently formatting the text of the FlyCnt, then
786 : // it has to get out of the way of the Frm anchored at paragraph!
787 : // pCurrFrm is the anchor of pNew?
788 : // #i26945#
789 118544 : const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
790 118544 : if( pTmp == pCurrFrm )
791 70844 : return true;
792 47700 : if( pTmp->IsTextFrm() && ( pTmp->IsInFly() || pTmp->IsInFootnote() ) )
793 : {
794 : // #i26945#
795 70 : Point aPos = _pAnchoredObj->GetObjRect().Pos();
796 70 : pTmp = GetVirtualUpper( pTmp, aPos );
797 : }
798 : // #i26945#
799 : // #115759#
800 : // If <pTmp> is a text frame inside a table, take the upper
801 : // of the anchor frame, which contains the anchor position.
802 47630 : else if ( pTmp->IsTextFrm() && pTmp->IsInTab() )
803 : {
804 : pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
805 189 : ->GetAnchorFrmContainingAnchPos()->GetUpper();
806 : }
807 : // #i28701# - consider all objects in same context,
808 : // if wrapping style is considered on object positioning.
809 : // Thus, text will wrap around negative positioned objects.
810 : // #i3317# - remove condition on checking,
811 : // if wrappings style is considered on object positioning.
812 : // Thus, text is wrapping around negative positioned objects.
813 : // #i35640# - no consideration of negative
814 : // positioned objects, if wrapping style isn't considered on
815 : // object position and former text wrapping is applied.
816 : // This condition is typically for documents imported from the
817 : // OpenOffice.org file format.
818 47700 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTextNode()->getIDocumentSettingAccess();
819 95858 : if ( ( pIDSA->get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
820 95400 : !pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ) &&
821 47700 : ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
822 : {
823 33119 : return true;
824 : }
825 :
826 14581 : const SwFrm* pHeader = 0;
827 34017 : if ( pCurrFrm->GetNext() != pTmp &&
828 29115 : ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
829 : // #i13832#, #i24135# wrap around objects in page header
830 29068 : ( !pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) &&
831 14079 : 0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
832 18887 : !pHeader->IsFooterFrm() &&
833 4808 : pCurrFrm->IsInDocBody() ) ) )
834 : {
835 4855 : if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
836 4808 : return true;
837 :
838 : // Compare indices:
839 : // The Index of the other is retrieved from the anchor attr.
840 47 : sal_uLong nTmpIndex = rNewA.GetContentAnchor()->nNode.GetIndex();
841 : // Now check whether the current paragraph is before the anchor
842 : // of the displaced object in the text, then we don't have to
843 : // get out of its way.
844 : // If possible determine Index via SwFormatAnchor because
845 : // otherwise it's quite expensive.
846 47 : if( ULONG_MAX == nIndex )
847 36 : nIndex = pCurrFrm->GetNode()->GetIndex();
848 :
849 47 : if( nIndex >= nTmpIndex )
850 0 : return true;
851 : }
852 : }
853 : }
854 15630 : return false;
855 : }
856 :
857 : // #i68520#
858 50596 : SwAnchoredObjList* SwTextFly::InitAnchoredObjList()
859 : {
860 : OSL_ENSURE( pCurrFrm, "InitFlyList: No Frame, no FlyList" );
861 : // #i68520#
862 : OSL_ENSURE( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
863 :
864 50596 : SWAP_IF_SWAPPED swap(const_cast<SwTextFrm *>(pCurrFrm));
865 :
866 50596 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
867 50596 : const size_t nCount = pSorted ? pSorted->size() : 0;
868 : // --> #108724# Page header/footer content doesn't have to wrap around
869 : // floating screen objects
870 50596 : const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
871 50596 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTextNode()->getIDocumentSettingAccess();
872 : // #i40155# - check, if frame is marked not to wrap
873 136459 : const bool bWrapAllowed = ( pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ||
874 151758 : ( !pCurrFrm->IsInFootnote() && !bFooterHeader ) );
875 :
876 50596 : bOn = false;
877 :
878 50596 : if( nCount && bWrapAllowed )
879 : {
880 : // #i68520#
881 35276 : mpAnchoredObjList = new SwAnchoredObjList();
882 :
883 : // #i28701# - consider complete frame area for new
884 : // text wrapping
885 35276 : SwRect aRect;
886 35276 : if ( pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) )
887 : {
888 9 : aRect = pCurrFrm->Prt();
889 9 : aRect += pCurrFrm->Frm().Pos();
890 : }
891 : else
892 : {
893 35267 : aRect = pCurrFrm->Frm();
894 : }
895 : // Make ourselves a little smaller than we are,
896 : // so that 1-Twip-overlappings are ignored (#49532)
897 35276 : SWRECTFN( pCurrFrm )
898 35276 : const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
899 35276 : const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
900 35276 : const bool bR2L = pCurrFrm->IsRightToLeft();
901 :
902 35276 : const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTextNode()->getIDocumentDrawModelAccess();
903 :
904 408498 : for( size_t i = 0; i < nCount; ++i )
905 : {
906 : // #i68520#
907 : // do not consider hidden objects
908 : // check, if object has to be considered for text wrap
909 : // #118809# - If requested, do not consider
910 : // objects in page header|footer for text frames not in page
911 : // header|footer. This is requested for the calculation of
912 : // the base offset for objects <SwTextFrm::CalcBaseOfstForFly()>
913 : // #i20505# Do not consider oversized objects
914 373222 : SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
915 : assert(pAnchoredObj);
916 1866110 : if ( !pAnchoredObj ||
917 1863375 : !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
918 1517630 : !pAnchoredObj->ConsiderForTextWrap() ||
919 324258 : ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
920 162129 : pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
921 : {
922 268235 : continue;
923 : }
924 :
925 337879 : const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
926 929997 : if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
927 254239 : (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
928 671087 : (aBound.*fnRect->fnGetBottom)() ) > 0 ||
929 640964 : nLeft > (aBound.*fnRect->fnGetRight)() ||
930 140476 : (aBound.*fnRect->fnGetHeight)() >
931 140476 : 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
932 : {
933 197549 : continue;
934 : }
935 :
936 : // #i26945# - pass <pAnchoredObj> to method
937 : // <GetTop(..)> instead of only the <SdrObject> instance of the
938 : // anchored object
939 140330 : if ( GetTop( pAnchoredObj, pCurrFrm->IsInFootnote(), bFooterHeader ) )
940 : {
941 : // OD 11.03.2003 #107862# - adjust insert position:
942 : // overlapping objects should be sorted from left to right and
943 : // inside left to right sorting from top to bottom.
944 : // If objects on the same position are found, they are sorted
945 : // on its width.
946 : // #i68520#
947 : {
948 : SwAnchoredObjList::iterator aInsPosIter =
949 : std::lower_bound( mpAnchoredObjList->begin(),
950 : mpAnchoredObjList->end(),
951 : pAnchoredObj,
952 109675 : AnchoredObjOrder( bR2L, fnRect ) );
953 :
954 109675 : mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
955 : }
956 :
957 109675 : const SwFormatSurround &rFlyFormat = pAnchoredObj->GetFrameFormat().GetSurround();
958 : // #i68520#
959 109675 : if ( rFlyFormat.IsAnchorOnly() &&
960 0 : pAnchoredObj->GetAnchorFrm() == GetMaster() )
961 : {
962 : const SwFormatVertOrient &rTmpFormat =
963 0 : pAnchoredObj->GetFrameFormat().GetVertOrient();
964 0 : if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
965 0 : nMinBottom = ( bVert && nMinBottom ) ?
966 0 : std::min( nMinBottom, aBound.Left() ) :
967 0 : std::max( nMinBottom, (aBound.*fnRect->fnGetBottom)() );
968 : }
969 :
970 109675 : bOn = true;
971 : }
972 : }
973 35276 : if( nMinBottom )
974 : {
975 0 : SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
976 0 : if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
977 0 : nMinBottom = nMax;
978 35276 : }
979 : }
980 : else
981 : {
982 : // #i68520#
983 15320 : mpAnchoredObjList = new SwAnchoredObjList();
984 : }
985 :
986 : // #i68520#
987 50596 : return mpAnchoredObjList;
988 : }
989 :
990 30319 : SwTwips SwTextFly::CalcMinBottom() const
991 : {
992 30319 : SwTwips nRet = 0;
993 30319 : const SwContentFrm *pLclMaster = GetMaster();
994 : OSL_ENSURE(pLclMaster, "SwTextFly without master");
995 30319 : const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : NULL;
996 30319 : const size_t nCount = pDrawObj ? pDrawObj->size() : 0;
997 30319 : if( nCount )
998 : {
999 1255 : SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
1000 2777 : for( size_t i = 0; i < nCount; ++i )
1001 : {
1002 1522 : SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
1003 1522 : const SwFormatSurround &rFlyFormat = pAnchoredObj->GetFrameFormat().GetSurround();
1004 1522 : if( rFlyFormat.IsAnchorOnly() )
1005 : {
1006 : const SwFormatVertOrient &rTmpFormat =
1007 0 : pAnchoredObj->GetFrameFormat().GetVertOrient();
1008 0 : if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
1009 : {
1010 0 : const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
1011 0 : if( aBound.Top() < nEndOfFrm )
1012 0 : nRet = std::max( nRet, aBound.Bottom() );
1013 : }
1014 : }
1015 : }
1016 1255 : SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
1017 1255 : pCurrFrm->GetUpper()->Prt().Bottom();
1018 1255 : if( nRet > nMax )
1019 0 : nRet = nMax;
1020 : }
1021 30319 : return nRet;
1022 : }
1023 :
1024 82257 : bool SwTextFly::ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const
1025 : {
1026 82257 : SWAP_IF_SWAPPED swap(const_cast<SwTextFrm *>(pCurrFrm));
1027 :
1028 82257 : bool bRet = false;
1029 : // #i68520#
1030 82257 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1031 82257 : if ( bOn && nCount > 0 )
1032 : {
1033 324586 : for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1034 : {
1035 : // #i68520#
1036 286730 : const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1037 :
1038 286730 : SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1039 :
1040 : // Optimierung
1041 286730 : SWRECTFN( pCurrFrm )
1042 286730 : if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
1043 5088 : break;
1044 : // #i68520#
1045 286229 : if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
1046 : {
1047 : // #i68520#
1048 55716 : const SwFormat* pFormat( &(pAnchoredObj->GetFrameFormat()) );
1049 55716 : const SwFormatSurround &rSur = pFormat->GetSurround();
1050 55716 : if( bAvoid )
1051 : {
1052 : // If the text flows below, it has no influence on
1053 : // formatting. In LineIter::DrawText() it is "just"
1054 : // necessary to clevely set the ClippingRegions
1055 54143 : const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1056 159225 : if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
1057 50939 : ( !rSur.IsAnchorOnly() ||
1058 : // #i68520#
1059 0 : GetMaster() == pAnchoredObj->GetAnchorFrm() ||
1060 0 : ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
1061 0 : (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
1062 57347 : || aRect.Top() == FAR_AWAY )
1063 102569 : continue;
1064 : }
1065 :
1066 : // #i58642#
1067 : // Compare <GetMaster()> instead of <pCurrFrm> with the anchor
1068 : // frame of the anchored object, because a follow frame have
1069 : // to ignore the anchored objects of its master frame.
1070 : // Note: Anchored objects are always registered at the master
1071 : // frame, exception are as-character anchored objects,
1072 : // but these aren't handled here.
1073 : // #i68520#
1074 5062 : if ( mbIgnoreCurrentFrame &&
1075 285 : GetMaster() == pAnchoredObj->GetAnchorFrm() )
1076 119 : continue;
1077 :
1078 4658 : if( pRect )
1079 : {
1080 : // #i68520#
1081 3085 : SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
1082 3085 : if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
1083 828 : continue;
1084 5658 : if( !bRet || (
1085 136 : ( !pCurrFrm->IsRightToLeft() &&
1086 68 : ( (aFly.*fnRect->fnGetLeft)() <
1087 136 : (pRect->*fnRect->fnGetLeft)() ) ) ||
1088 68 : ( pCurrFrm->IsRightToLeft() &&
1089 0 : ( (aFly.*fnRect->fnGetRight)() >
1090 0 : (pRect->*fnRect->fnGetRight)() ) ) ) )
1091 2761 : *pRect = aFly;
1092 2829 : if( rSur.IsContour() )
1093 : {
1094 316 : bRet = true;
1095 316 : continue;
1096 : }
1097 : }
1098 4086 : bRet = true;
1099 4086 : break;
1100 : }
1101 : }
1102 : }
1103 :
1104 82257 : return bRet;
1105 : }
1106 :
1107 : // #i68520#
1108 2917 : SwAnchoredObjList::size_type SwTextFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
1109 : {
1110 2917 : SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
1111 2917 : SwAnchoredObjList::size_type nRet = 0;
1112 6757 : while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
1113 923 : ++nRet;
1114 2917 : return nRet;
1115 : }
1116 :
1117 : // #i68520#
1118 546 : void SwTextFly::CalcRightMargin( SwRect &rFly,
1119 : SwAnchoredObjList::size_type nFlyPos,
1120 : const SwRect &rLine ) const
1121 : {
1122 : // Usually the right margin is the right margin of the Printarea
1123 : OSL_ENSURE( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
1124 : "SwTextFly::CalcRightMargin with swapped frame" );
1125 546 : SWRECTFN( pCurrFrm )
1126 : // #118796# - correct determination of right of printing area
1127 546 : SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1128 546 : SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
1129 546 : SwRect aLine( rLine );
1130 546 : (aLine.*fnRect->fnSetRight)( nRight );
1131 546 : (aLine.*fnRect->fnSetLeft)( (rFly.*fnRect->fnGetLeft)() );
1132 :
1133 : // It is possible that there is another object that is _above_ us
1134 : // and protrudes into the same line.
1135 : // Flys with run-through are invisible for those below, i.e., they
1136 : // are ignored for computing the margins of other Flys.
1137 : // 3301: pNext->Frm().IsOver( rLine ) is necessary
1138 : // #i68520#
1139 : SwSurround eSurroundForTextWrap;
1140 :
1141 546 : bool bStop = false;
1142 : // #i68520#
1143 546 : SwAnchoredObjList::size_type nPos = 0;
1144 :
1145 : // #i68520#
1146 2040 : while( nPos < mpAnchoredObjList->size() && !bStop )
1147 : {
1148 948 : if( nPos == nFlyPos )
1149 : {
1150 546 : ++nPos;
1151 1220 : continue;
1152 : }
1153 : // #i68520#
1154 402 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
1155 402 : if ( pNext == mpCurrAnchoredObj )
1156 0 : continue;
1157 402 : eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1158 402 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1159 128 : continue;
1160 :
1161 : const SwRect aTmp( SwContourCache::CalcBoundRect
1162 274 : ( pNext, aLine, pCurrFrm, nFlyRight, true ) );
1163 274 : SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
1164 :
1165 : // optimization:
1166 : // Record in nNextTop at which Y-position frame related changes are
1167 : // likely. This is so that, despite only looking at frames in the
1168 : // current line height, for frames without wrap the line height is
1169 : // incremented so that with a single line the lower border of the frame
1170 : // (or possibly the upper border of another frame) is reached.
1171 : // Especially in HTML documents there are often (dummy) paragraphs in
1172 : // 2 pt font, and they used to only evade big frames after huge numbers
1173 : // of empty lines.
1174 274 : const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
1175 274 : if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 )
1176 : {
1177 145 : if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 )
1178 60 : SetNextTop( nTmpTop ); // upper border of next frame
1179 : }
1180 129 : else if (!(aTmp.*fnRect->fnGetWidth)()) // typical for Objects with contour wrap
1181 : { // For Objects with contour wrap that start before the current
1182 : // line, and end below it, but do not actually overlap it, the
1183 : // optimization has to be disabled, because the circumstances
1184 : // can change in the next line.
1185 0 : if( ! (aTmp.*fnRect->fnGetHeight)() ||
1186 0 : (*fnRect->fnYDiff)( (aTmp.*fnRect->fnGetBottom)(),
1187 0 : (aLine.*fnRect->fnGetTop)() ) > 0 )
1188 0 : SetNextTop( 0 );
1189 : }
1190 274 : if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
1191 : {
1192 65 : nFlyRight = nTmpRight;
1193 65 : if( SURROUND_RIGHT == eSurroundForTextWrap ||
1194 : SURROUND_PARALLEL == eSurroundForTextWrap )
1195 : {
1196 : // overrule the FlyFrm
1197 0 : if( nRight > nFlyRight )
1198 0 : nRight = nFlyRight;
1199 0 : bStop = true;
1200 : }
1201 : }
1202 : }
1203 546 : (rFly.*fnRect->fnSetRight)( nRight );
1204 546 : }
1205 :
1206 : // #i68520#
1207 442 : void SwTextFly::CalcLeftMargin( SwRect &rFly,
1208 : SwAnchoredObjList::size_type nFlyPos,
1209 : const SwRect &rLine ) const
1210 : {
1211 : OSL_ENSURE( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
1212 : "SwTextFly::CalcLeftMargin with swapped frame" );
1213 442 : SWRECTFN( pCurrFrm )
1214 : // #118796# - correct determination of left of printing area
1215 442 : SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1216 442 : const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();
1217 :
1218 442 : if( nLeft > nFlyLeft )
1219 42 : nLeft = rFly.Left();
1220 :
1221 442 : SwRect aLine( rLine );
1222 442 : (aLine.*fnRect->fnSetLeft)( nLeft );
1223 :
1224 : // It is possible that there is another object that is _above_ us
1225 : // and protrudes into the same line.
1226 : // Flys with run-through are invisible for those below, i.e., they
1227 : // are ignored for computing the margins of other Flys.
1228 : // 3301: pNext->Frm().IsOver( rLine ) is necessary
1229 :
1230 : // #i68520#
1231 442 : SwAnchoredObjList::size_type nMyPos = nFlyPos;
1232 884 : while( ++nFlyPos < mpAnchoredObjList->size() )
1233 : {
1234 : // #i68520#
1235 120 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1236 120 : const SwRect aTmp( pNext->GetObjRectWithSpaces() );
1237 120 : if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
1238 120 : break;
1239 : }
1240 :
1241 1481 : while( nFlyPos )
1242 : {
1243 597 : if( --nFlyPos == nMyPos )
1244 999 : continue;
1245 : // #i68520#
1246 155 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1247 155 : if( pNext == mpCurrAnchoredObj )
1248 0 : continue;
1249 155 : SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1250 155 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1251 115 : continue;
1252 :
1253 : const SwRect aTmp( SwContourCache::CalcBoundRect
1254 40 : ( pNext, aLine, pCurrFrm, nFlyLeft, false ) );
1255 :
1256 40 : if( (aTmp.*fnRect->fnGetLeft)() < nFlyLeft && aTmp.IsOver( aLine ) )
1257 : {
1258 : // #118796# - no '+1', because <..fnGetRight>
1259 : // returns the correct value.
1260 0 : SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
1261 0 : if ( nLeft <= nTmpRight )
1262 0 : nLeft = nTmpRight;
1263 :
1264 0 : break;
1265 : }
1266 : }
1267 442 : (rFly.*fnRect->fnSetLeft)( nLeft );
1268 442 : }
1269 :
1270 : // #i68520#
1271 3085 : SwRect SwTextFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
1272 : const SwRect &rLine ) const
1273 : {
1274 3085 : SWRECTFN( pCurrFrm )
1275 :
1276 3085 : const long nXPos = pCurrFrm->IsRightToLeft() ?
1277 : rLine.Right() :
1278 3085 : (rLine.*fnRect->fnGetLeft)();
1279 :
1280 : SwRect aFly = mbIgnoreContour ?
1281 450 : pAnchoredObj->GetObjRectWithSpaces() :
1282 : SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
1283 3535 : nXPos, ! pCurrFrm->IsRightToLeft() );
1284 :
1285 3085 : if( !aFly.Width() )
1286 168 : return aFly;
1287 :
1288 : // so the line may grow up to the lower edge of the frame
1289 2917 : SetNextTop( (aFly.*fnRect->fnGetBottom)() );
1290 2917 : SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );
1291 :
1292 : // LEFT and RIGHT, we grow the rectangle.
1293 : // We have some problems, when several frames are to be seen.
1294 : // At the moment, only the easier case is assumed:
1295 : // + LEFT means that the text must flow on the left of the frame,
1296 : // that is the frame expands to the right edge of the print area
1297 : // or to the next frame.
1298 : // + RIGHT is the opposite.
1299 : // Otherwise the set distance between text and frame is always
1300 : // added up.
1301 2917 : switch( _GetSurroundForTextWrap( pAnchoredObj ) )
1302 : {
1303 : case SURROUND_LEFT :
1304 : {
1305 108 : CalcRightMargin( aFly, nFlyPos, rLine );
1306 108 : break;
1307 : }
1308 : case SURROUND_RIGHT :
1309 : {
1310 4 : CalcLeftMargin( aFly, nFlyPos, rLine );
1311 4 : break;
1312 : }
1313 : case SURROUND_NONE :
1314 : {
1315 438 : CalcRightMargin( aFly, nFlyPos, rLine );
1316 438 : CalcLeftMargin( aFly, nFlyPos, rLine );
1317 438 : break;
1318 : }
1319 : default:
1320 2367 : break;
1321 : }
1322 2917 : return aFly;
1323 : }
1324 :
1325 : // #i68520#
1326 :
1327 : // Wrap only on sides with at least 2cm space for the text
1328 : #define TEXT_MIN 1134
1329 :
1330 : // MS Word wraps on sides with even less space (value guessed).
1331 : #define TEXT_MIN_SMALL 300
1332 :
1333 : // Wrap on both sides up to a frame width of 1.5cm
1334 : #define FRAME_MAX 850
1335 :
1336 3474 : SwSurround SwTextFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
1337 : {
1338 3474 : const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
1339 3474 : const SwFormatSurround &rFlyFormat = pFormat->GetSurround();
1340 3474 : SwSurround eSurroundForTextWrap = rFlyFormat.GetSurround();
1341 :
1342 3474 : if( rFlyFormat.IsAnchorOnly() && pAnchoredObj->GetAnchorFrm() != GetMaster() )
1343 : {
1344 0 : const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1345 0 : if ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
1346 0 : (FLY_AT_CHAR == rAnchor.GetAnchorId()))
1347 : {
1348 0 : return SURROUND_NONE;
1349 : }
1350 : }
1351 :
1352 : // in cause of run-through and nowrap ignore smartly
1353 3474 : if( SURROUND_THROUGHT == eSurroundForTextWrap ||
1354 : SURROUND_NONE == eSurroundForTextWrap )
1355 882 : return eSurroundForTextWrap;
1356 :
1357 : // left is left and right is right
1358 2592 : if ( pCurrFrm->IsRightToLeft() )
1359 : {
1360 0 : if ( SURROUND_LEFT == eSurroundForTextWrap )
1361 0 : eSurroundForTextWrap = SURROUND_RIGHT;
1362 0 : else if ( SURROUND_RIGHT == eSurroundForTextWrap )
1363 0 : eSurroundForTextWrap = SURROUND_LEFT;
1364 : }
1365 :
1366 : // "ideal page wrap":
1367 2592 : if ( SURROUND_IDEAL == eSurroundForTextWrap )
1368 : {
1369 240 : SWRECTFN( pCurrFrm )
1370 240 : const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1371 240 : const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1372 240 : const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1373 240 : long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
1374 240 : long nFlyRight = (aRect.*fnRect->fnGetRight)();
1375 :
1376 240 : if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
1377 0 : eSurroundForTextWrap = SURROUND_PARALLEL;
1378 : else
1379 : {
1380 240 : long nLeft = nFlyLeft - nCurrLeft;
1381 240 : long nRight = nCurrRight - nFlyRight;
1382 240 : if( nFlyRight - nFlyLeft > FRAME_MAX )
1383 : {
1384 225 : if( nLeft < nRight )
1385 27 : nLeft = 0;
1386 : else
1387 198 : nRight = 0;
1388 : }
1389 240 : const int textMin = GetMaster()->GetNode()
1390 240 : ->getIDocumentSettingAccess()->get(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL )
1391 240 : ? TEXT_MIN_SMALL : TEXT_MIN;
1392 240 : if( nLeft < textMin )
1393 108 : nLeft = 0;
1394 240 : if( nRight < textMin )
1395 221 : nRight = 0;
1396 240 : if( nLeft )
1397 132 : eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
1398 : else
1399 108 : eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
1400 : }
1401 : }
1402 :
1403 2592 : return eSurroundForTextWrap;
1404 : }
1405 :
1406 0 : bool SwTextFly::IsAnyFrm( const SwRect &rLine ) const
1407 : {
1408 :
1409 0 : SWAP_IF_SWAPPED swap(const_cast<SwTextFrm *>(pCurrFrm));
1410 :
1411 : OSL_ENSURE( bOn, "IsAnyFrm: Why?" );
1412 :
1413 0 : return ForEach( rLine, NULL, false );
1414 177 : }
1415 :
1416 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|