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