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 "pagefrm.hxx"
24 : #include "rootfrm.hxx"
25 : #include "pam.hxx"
26 : #include "swregion.hxx"
27 : #include "dflyobj.hxx"
28 : #include "flyfrm.hxx"
29 : #include "frmtool.hxx"
30 : #include "porfly.hxx"
31 : #include "porfld.hxx"
32 : #include "txtfly.hxx"
33 : #include "txtpaint.hxx"
34 : #include "txtatr.hxx"
35 : #include "notxtfrm.hxx"
36 : #include "fmtcnct.hxx"
37 : #include "inftxt.hxx"
38 : #include <pormulti.hxx>
39 : #include <svx/obj3d.hxx>
40 : #include <editeng/txtrange.hxx>
41 : #include <editeng/lrspitem.hxx>
42 : #include <editeng/ulspitem.hxx>
43 : // #i28701#
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 27496 : AnchoredObjOrder( const bool bR2L,
74 : SwRectFn fnRect )
75 : : mbR2L( bR2L ),
76 27496 : mfnRect( fnRect )
77 27496 : {}
78 :
79 88115 : bool operator()( const SwAnchoredObject* pListedAnchoredObj,
80 : const SwAnchoredObject* pNewAnchoredObj )
81 : {
82 88115 : const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
83 88115 : const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
84 88115 : if ( ( mbR2L &&
85 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
86 177943 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
87 176230 : ( !mbR2L &&
88 88115 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
89 88115 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
90 : {
91 : SwTwips nTopDiff =
92 1713 : (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
93 3426 : (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
94 1713 : if ( nTopDiff == 0 &&
95 0 : ( ( mbR2L &&
96 0 : ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
97 140 : (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
98 280 : ( !mbR2L &&
99 140 : ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
100 140 : (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
101 : {
102 0 : return true;
103 : }
104 1713 : else if ( nTopDiff > 0 )
105 : {
106 1105 : return true;
107 : }
108 : }
109 86402 : else if ( ( mbR2L &&
110 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
111 210737 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
112 172804 : ( !mbR2L &&
113 86402 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
114 86402 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
115 : {
116 37933 : return true;
117 : }
118 :
119 49077 : return false;
120 : }
121 : };
122 : }
123 :
124 1 : SwContourCache::SwContourCache() :
125 1 : nPntCnt( 0 ), nObjCnt( 0 )
126 : {
127 1 : memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) );
128 1 : memset( pTextRanger, 0, sizeof(pTextRanger) );
129 1 : }
130 :
131 1 : SwContourCache::~SwContourCache()
132 : {
133 1 : for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
134 : ;
135 1 : }
136 :
137 8 : void SwContourCache::ClrObject( MSHORT nPos )
138 : {
139 : OSL_ENSURE( pTextRanger[ nPos ], "ClrObject: Already cleared. Good Bye!" );
140 8 : nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
141 8 : delete pTextRanger[ nPos ];
142 8 : --nObjCnt;
143 8 : memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1,
144 16 : ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
145 8 : memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
146 16 : ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
147 8 : }
148 :
149 2149 : void ClrContourCache( const SdrObject *pObj )
150 : {
151 2149 : if( pContourCache && pObj )
152 20 : for( MSHORT i = 0; i < pContourCache->GetCount(); ++i )
153 8 : if( pObj == pContourCache->GetObject( i ) )
154 : {
155 8 : pContourCache->ClrObject( i );
156 8 : break;
157 : }
158 2149 : }
159 :
160 1802 : void ClrContourCache()
161 : {
162 1802 : if( pContourCache )
163 : {
164 84 : for( MSHORT i = 0; i < pContourCache->GetCount();
165 0 : delete pContourCache->pTextRanger[ i++ ] )
166 : ;
167 42 : pContourCache->nObjCnt = 0;
168 42 : pContourCache->nPntCnt = 0;
169 : }
170 1802 : }
171 :
172 : // #i68520#
173 1883 : 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 1883 : SwRect aRet;
180 1883 : const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
181 1931 : if( pFmt->GetSurround().IsContour() &&
182 48 : ( !pAnchoredObj->ISA(SwFlyFrm) ||
183 48 : ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
184 24 : static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) )
185 : {
186 24 : aRet = pAnchoredObj->GetObjRectWithSpaces();
187 24 : if( aRet.IsOver( rLine ) )
188 : {
189 24 : if( !pContourCache )
190 1 : pContourCache = new SwContourCache;
191 :
192 48 : aRet = pContourCache->ContourRect(
193 24 : pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
194 : }
195 : else
196 0 : aRet.Width( 0 );
197 : }
198 : else
199 : {
200 1859 : aRet = pAnchoredObj->GetObjRectWithSpaces();
201 : }
202 :
203 1883 : return aRet;
204 : }
205 :
206 24 : 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 24 : SwRect aRet;
211 24 : MSHORT nPos = 0; // Suche im Cache ...
212 48 : while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
213 0 : ++nPos;
214 24 : if( GetCount() == nPos ) // nicht gefunden
215 : {
216 8 : if( nObjCnt == POLY_CNT )
217 : {
218 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
219 0 : delete pTextRanger[ nObjCnt ];
220 : }
221 8 : ::basegfx::B2DPolyPolygon aPolyPolygon;
222 8 : ::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;
223 :
224 8 : 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 8 : PolyPolygon aPoly;
229 8 : if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) )
230 16 : aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)->
231 16 : GetFlyFrm()->Frm().SVRect() );
232 8 : aPolyPolygon.clear();
233 8 : aPolyPolygon.append(aPoly.getB2DPolyPolygon());
234 : }
235 : else
236 : {
237 0 : if( !pObj->ISA( E3dObject ) )
238 : {
239 0 : aPolyPolygon = pObj->TakeXorPoly();
240 : }
241 :
242 0 : ::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour());
243 0 : pPolyPolygon = new ::basegfx::B2DPolyPolygon(aContourPoly);
244 : }
245 8 : const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace();
246 8 : const SvxULSpaceItem &rULSpace = pFmt->GetULSpace();
247 8 : memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
248 8 : memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
249 8 : pSdrObj[ 0 ] = pObj; // due to #37347 the Object must be entered only
250 : // after GetContour()
251 : pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
252 16 : (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(),
253 16 : pFmt->GetSurround().IsOutside(), false, pFrm->IsVertical() );
254 8 : pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
255 8 : pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );
256 :
257 8 : delete pPolyPolygon;
258 :
259 8 : nPntCnt += pTextRanger[ 0 ]->GetPointCount();
260 16 : while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
261 : {
262 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
263 0 : delete pTextRanger[ nObjCnt ];
264 8 : }
265 : }
266 16 : else if( nPos )
267 : {
268 0 : const SdrObject* pTmpObj = pSdrObj[ nPos ];
269 0 : TextRanger* pTmpRanger = pTextRanger[ nPos ];
270 0 : memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nPos * sizeof( SdrObject* ) );
271 0 : memmove( pTextRanger + 1, pTextRanger, nPos * sizeof( TextRanger* ) );
272 0 : pSdrObj[ 0 ] = pTmpObj;
273 0 : pTextRanger[ 0 ] = pTmpRanger;
274 : }
275 24 : SWRECTFN( pFrm )
276 24 : long nTmpTop = (rLine.*fnRect->fnGetTop)();
277 : // fnGetBottom is top + height
278 24 : long nTmpBottom = (rLine.*fnRect->fnGetBottom)();
279 :
280 24 : Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );
281 :
282 24 : LongDqPtr pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );
283 :
284 : MSHORT nCount;
285 24 : if( 0 != ( nCount = pTmp->size() ) )
286 : {
287 24 : MSHORT nIdx = 0;
288 48 : while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
289 0 : ++nIdx;
290 24 : bool bOdd = (nIdx % 2);
291 24 : bool bSet = true;
292 24 : if( bOdd )
293 0 : --nIdx; // within interval
294 24 : 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 24 : if( bSet && nIdx < nCount )
303 : {
304 48 : (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
305 72 : (rLine.*fnRect->fnGetHeight)() );
306 24 : (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
307 24 : (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
308 : }
309 : }
310 24 : return aRet;
311 : }
312 :
313 42233 : SwTxtFly::SwTxtFly() :
314 : pPage(0),
315 : mpCurrAnchoredObj(0),
316 : pCurrFrm(0),
317 : pMaster(0),
318 : mpAnchoredObjList(0),
319 : nMinBottom(0),
320 : nNextTop(0),
321 42233 : nIndex(0)
322 : {
323 42233 : }
324 :
325 64177 : SwTxtFly::SwTxtFly( const SwTxtFrm *pFrm )
326 : {
327 64177 : CtorInitTxtFly( pFrm );
328 64177 : }
329 :
330 38207 : SwTxtFly::SwTxtFly( const SwTxtFly& rTxtFly )
331 : {
332 38207 : pPage = rTxtFly.pPage;
333 38207 : mpCurrAnchoredObj = rTxtFly.mpCurrAnchoredObj;
334 38207 : pCurrFrm = rTxtFly.pCurrFrm;
335 38207 : pMaster = rTxtFly.pMaster;
336 38207 : if( rTxtFly.mpAnchoredObjList )
337 : {
338 13896 : mpAnchoredObjList = new SwAnchoredObjList( *(rTxtFly.mpAnchoredObjList) );
339 : }
340 : else
341 : {
342 24311 : mpAnchoredObjList = NULL;
343 : }
344 :
345 38207 : bOn = rTxtFly.bOn;
346 38207 : bTopRule = rTxtFly.bTopRule;
347 38207 : nMinBottom = rTxtFly.nMinBottom;
348 38207 : nNextTop = rTxtFly.nNextTop;
349 38207 : nIndex = rTxtFly.nIndex;
350 38207 : mbIgnoreCurrentFrame = rTxtFly.mbIgnoreCurrentFrame;
351 38207 : mbIgnoreContour = rTxtFly.mbIgnoreContour;
352 38207 : mbIgnoreObjsInHeaderFooter = rTxtFly.mbIgnoreObjsInHeaderFooter;
353 38207 : }
354 :
355 144617 : SwTxtFly::~SwTxtFly()
356 : {
357 144617 : delete mpAnchoredObjList;
358 144617 : }
359 :
360 106410 : void SwTxtFly::CtorInitTxtFly( const SwTxtFrm *pFrm )
361 : {
362 106410 : mbIgnoreCurrentFrame = false;
363 106410 : mbIgnoreContour = false;
364 : // #118809#
365 106410 : mbIgnoreObjsInHeaderFooter = false;
366 106410 : pPage = pFrm->FindPageFrm();
367 106410 : const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
368 : // #i68520#
369 106410 : mpCurrAnchoredObj = pTmp;
370 106410 : pCurrFrm = pFrm;
371 106410 : pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
372 : // #i68520#
373 106410 : mpAnchoredObjList = NULL;
374 : // If we're not overlapped by a frame or if a FlyCollection does not exist
375 : // at all, we switch off forever.
376 : // It could be, however, that a line is added while formatting, that
377 : // extends into a frame.
378 : // That's why we do not optimize for: bOn = pSortedFlys && IsAnyFrm();
379 106410 : bOn = pPage->GetSortedObjs() != 0;
380 106410 : bTopRule = true;
381 106410 : nMinBottom = 0;
382 106410 : nNextTop = 0;
383 106410 : nIndex = ULONG_MAX;
384 106410 : }
385 :
386 43808 : SwRect SwTxtFly::_GetFrm( const SwRect &rRect, bool bTop ) const
387 : {
388 43808 : SwRect aRet;
389 43808 : if( ForEach( rRect, &aRet, true ) )
390 : {
391 1971 : SWRECTFN( pCurrFrm )
392 1971 : if( bTop )
393 1971 : (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );
394 :
395 : // 8110: Do not always adapt the bottom
396 1971 : const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
397 1971 : const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
398 2354 : if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
399 383 : (aRet.*fnRect->fnGetHeight)() < 0 )
400 1588 : (aRet.*fnRect->fnSetBottom)( nRectBottom );
401 : }
402 43808 : return aRet;
403 : }
404 :
405 3817 : bool SwTxtFly::IsAnyFrm() const
406 : {
407 3817 : SWAP_IF_SWAPPED( pCurrFrm )
408 :
409 : OSL_ENSURE( bOn, "IsAnyFrm: Why?" );
410 7634 : SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
411 7634 : pCurrFrm->Prt().SSize() );
412 :
413 3817 : const bool bRet = ForEach( aRect, NULL, false );
414 3817 : UNDO_SWAP( pCurrFrm )
415 3817 : return bRet;
416 : }
417 :
418 3229 : bool SwTxtFly::IsAnyObj( const SwRect &rRect ) const
419 : {
420 : OSL_ENSURE( bOn, "SwTxtFly::IsAnyObj: Who's knocking?" );
421 :
422 3229 : SwRect aRect( rRect );
423 3229 : if ( aRect.IsEmpty() )
424 6458 : aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
425 6458 : pCurrFrm->Prt().SSize() );
426 :
427 3229 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
428 3229 : if( pSorted ) // bOn actually makes sure that we have objects on the side,
429 : // but who knows who deleted somehting in the meantime?
430 : {
431 9494 : for ( MSHORT i = 0; i < pSorted->Count(); ++i )
432 : {
433 7261 : const SwAnchoredObject* pObj = (*pSorted)[i];
434 :
435 7261 : const SwRect aBound( pObj->GetObjRectWithSpaces() );
436 :
437 : // Optimization
438 7261 : if( pObj->GetObjRect().Left() > aRect.Right() )
439 2368 : continue;
440 :
441 : // #i68520#
442 4893 : if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
443 996 : return true;
444 : }
445 : }
446 2233 : return false;
447 : }
448 :
449 1410 : const SwCntntFrm* SwTxtFly::_GetMaster()
450 : {
451 1410 : pMaster = pCurrFrm;
452 4759 : while( pMaster && pMaster->IsFollow() )
453 1939 : pMaster = (SwCntntFrm*)pMaster->FindMaster();
454 1410 : return pMaster;
455 : }
456 :
457 166 : bool SwTxtFly::DrawTextOpaque( SwDrawTextInfo &rInf )
458 : {
459 166 : SwSaveClip aClipSave( rInf.GetpOut() );
460 166 : SwRect aRect( rInf.GetPos(), rInf.GetSize() );
461 166 : if( rInf.GetSpace() )
462 : {
463 10 : sal_Int32 nTmpLen = COMPLETE_STRING == rInf.GetLen() ? rInf.GetText().getLength() :
464 10 : rInf.GetLen();
465 10 : if( rInf.GetSpace() > 0 )
466 : {
467 10 : sal_Int32 nSpaceCnt = 0;
468 10 : const sal_Int32 nEndPos = rInf.GetIdx() + nTmpLen;
469 532 : for( sal_Int32 nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos )
470 : {
471 522 : if( CH_BLANK == rInf.GetText()[ nPos ] )
472 75 : ++nSpaceCnt;
473 : }
474 10 : if( nSpaceCnt )
475 8 : aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
476 : }
477 : else
478 0 : aRect.Width( aRect.Width() - nTmpLen * rInf.GetSpace() );
479 : }
480 :
481 166 : if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
482 : {
483 89 : SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
484 89 : aRect.Intersection( aClipRect );
485 : }
486 :
487 332 : SwRegionRects aRegion( aRect );
488 :
489 166 : bool bOpaque = false;
490 : // #i68520#
491 : const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
492 0 : ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
493 166 : : SAL_MAX_UINT32;
494 : OSL_ENSURE( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
495 :
496 : // #i68520#
497 166 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
498 166 : if ( bOn && nCount > 0 )
499 : {
500 166 : MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
501 465 : for( MSHORT i = 0; i < nCount; ++i )
502 : {
503 : // #i68520#
504 299 : const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
505 538 : if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
506 598 : mpCurrAnchoredObj != pTmpAnchoredObj )
507 : {
508 : // #i68520#
509 239 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj);
510 239 : if( aRegion.GetOrigin().IsOver( pFly->Frm() ) )
511 : {
512 11 : const SwFrmFmt *pFmt = pFly->GetFmt();
513 11 : const SwFmtSurround &rSur = pFmt->GetSurround();
514 11 : const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
515 : // Only the ones who are opaque and more to the top
516 22 : if( !( pFly->IsBackgroundTransparent()
517 22 : || pFly->IsShadowTransparent() ) &&
518 22 : SURROUND_THROUGHT == rSur.GetSurround() &&
519 11 : ( !rSur.IsAnchorOnly() ||
520 : // #i68520#
521 0 : GetMaster() == pFly->GetAnchorFrm() ||
522 0 : ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
523 0 : (FLY_AT_CHAR != rAnchor.GetAnchorId())
524 : )
525 11 : ) &&
526 : // #i68520#
527 22 : pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
528 0 : nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
529 : )
530 : {
531 : // Except for the content is transparent
532 : const SwNoTxtFrm *pNoTxt =
533 0 : pFly->Lower() && pFly->Lower()->IsNoTxtFrm()
534 0 : ? (SwNoTxtFrm*)pFly->Lower()
535 0 : : 0;
536 0 : if ( !pNoTxt ||
537 0 : (!pNoTxt->IsTransparent() && !rSur.IsContour()) )
538 : {
539 0 : bOpaque = true;
540 0 : aRegion -= pFly->Frm();
541 : }
542 : }
543 : }
544 : }
545 : }
546 : }
547 :
548 166 : Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
549 166 : const Point aOldPos(rInf.GetPos());
550 166 : rInf.SetPos( aPos );
551 :
552 166 : if( !bOpaque )
553 : {
554 166 : if( rInf.GetKern() )
555 1 : rInf.GetFont()->_DrawStretchText( rInf );
556 : else
557 165 : rInf.GetFont()->_DrawText( rInf );
558 166 : rInf.SetPos(aOldPos);
559 166 : return false;
560 : }
561 0 : else if( !aRegion.empty() )
562 : {
563 : // What a huge effort ...
564 0 : SwSaveClip aClipVout( rInf.GetpOut() );
565 0 : for( MSHORT i = 0; i < aRegion.size(); ++i )
566 : {
567 0 : SwRect &rRect = aRegion[i];
568 0 : if( rRect != aRegion.GetOrigin() )
569 0 : aClipVout.ChgClip( rRect );
570 0 : if( rInf.GetKern() )
571 0 : rInf.GetFont()->_DrawStretchText( rInf );
572 : else
573 0 : rInf.GetFont()->_DrawText( rInf );
574 0 : }
575 : }
576 0 : rInf.SetPos(aOldPos);
577 166 : return true;
578 : }
579 :
580 44 : void SwTxtFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
581 : const SwTxtPaintInfo &rInf, bool bNoGraphic )
582 : {
583 44 : SwRegionRects aRegion( rRect );
584 : OSL_ENSURE( !bTopRule, "DrawFlyRect: Wrong TopRule" );
585 : // #i68520#
586 44 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
587 44 : if ( bOn && nCount > 0 )
588 : {
589 44 : MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
590 107 : for( MSHORT i = 0; i < nCount; ++i )
591 : {
592 : // #i68520#
593 63 : const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
594 63 : if (mpCurrAnchoredObj == pAnchoredObjTmp)
595 0 : continue;
596 :
597 : // #i68520#
598 63 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
599 63 : if (pFly)
600 : {
601 : // #i68520#
602 63 : const SwFmtSurround& rSur = pAnchoredObjTmp->GetFrmFmt().GetSurround();
603 :
604 : // OD 24.01.2003 #106593# - correct clipping of fly frame area.
605 : // Consider that fly frame background/shadow can be transparent
606 : // and <SwAlignRect(..)> fly frame area
607 : // #i47804# - consider transparent graphics
608 : // and OLE objects.
609 : bool bClipFlyArea =
610 63 : ( ( SURROUND_THROUGHT == rSur.GetSurround() )
611 : // #i68520#
612 0 : ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
613 126 : : !rSur.IsContour() ) &&
614 126 : !pFly->IsBackgroundTransparent() &&
615 303 : !pFly->IsShadowTransparent() &&
616 126 : ( !pFly->Lower() ||
617 75 : !pFly->Lower()->IsNoTxtFrm() ||
618 75 : !static_cast<const SwNoTxtFrm*>(pFly->Lower())->IsTransparent() );
619 63 : if ( bClipFlyArea )
620 : {
621 : // #i68520#
622 51 : SwRect aFly( pAnchoredObjTmp->GetObjRect() );
623 : // OD 24.01.2003 #106593#
624 51 : ::SwAlignRect( aFly, pPage->getRootFrm()->GetCurrShell() );
625 51 : if( aFly.Width() > 0 && aFly.Height() > 0 )
626 51 : aRegion -= aFly;
627 : }
628 : }
629 : }
630 : }
631 :
632 88 : for( MSHORT i = 0; i < aRegion.size(); ++i )
633 : {
634 44 : if ( bNoGraphic )
635 : {
636 44 : pOut->DrawRect( aRegion[i].SVRect() );
637 : }
638 : else
639 : {
640 0 : if(((SvxBrushItem*)-1) != rInf.GetBrushItem())
641 : {
642 0 : ::DrawGraphic(rInf.GetBrushItem(), pOut, rInf.GetBrushRect(), aRegion[i] );
643 : }
644 : else
645 : {
646 : OSL_ENSURE(false, "DrawRect: Uninitialized BrushItem!" );
647 : }
648 : }
649 44 : }
650 44 : }
651 :
652 : // #i26945# - change first parameter
653 : // Now it's the <SwAnchoredObject> instance of the floating screen object
654 41241 : bool SwTxtFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
655 : const bool bInFtn,
656 : const bool bInFooterOrHeader )
657 : {
658 : // #i68520#
659 : // <mpCurrAnchoredObj> is set, if <pCurrFrm> is inside a fly frame
660 41241 : if( _pAnchoredObj != mpCurrAnchoredObj )
661 : {
662 : // #i26945#
663 38521 : const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
664 : // #102344# Ignore connectors which have one or more connections
665 38521 : if(pNew && pNew->ISA(SdrEdgeObj))
666 : {
667 0 : if(((SdrEdgeObj*)pNew)->GetConnectedNode(true)
668 0 : || ((SdrEdgeObj*)pNew)->GetConnectedNode(false))
669 : {
670 0 : return false;
671 : }
672 : }
673 :
674 38521 : if( ( bInFtn || bInFooterOrHeader ) && bTopRule )
675 : {
676 : // #i26945#
677 0 : const SwFrmFmt& rFrmFmt = _pAnchoredObj->GetFrmFmt();
678 0 : const SwFmtAnchor& rNewA = rFrmFmt.GetAnchor();
679 0 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
680 : {
681 0 : if ( bInFtn )
682 0 : return false;
683 :
684 0 : if ( bInFooterOrHeader )
685 : {
686 0 : SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() );
687 0 : bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
688 0 : aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
689 0 : if( bVertPrt )
690 0 : return false;
691 : }
692 : }
693 : }
694 :
695 : // #i68520#
696 : // bEvade: consider pNew, if we are not inside a fly
697 : // consider pNew, if pNew is lower of <mpCurrAnchoredObj>
698 44766 : bool bEvade = !mpCurrAnchoredObj ||
699 44766 : Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);
700 :
701 38521 : if ( !bEvade )
702 : {
703 : // We are currently inside a fly frame and pNew is not
704 : // inside this fly frame. We can do some more checks if
705 : // we have to consider pNew.
706 :
707 : // If bTopRule is not set, we ignore the frame types.
708 : // We directly check the z-order
709 6239 : if ( !bTopRule )
710 863 : bEvade = true;
711 : else
712 : {
713 : // Within chained Flys we only avoid Lower
714 : // #i68520#
715 5376 : const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain();
716 5376 : if ( !rChain.GetPrev() && !rChain.GetNext() )
717 : {
718 : // #i26945#
719 5376 : const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
720 : // #i68520#
721 5376 : const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor();
722 :
723 : // If <mpCurrAnchoredObj> is anchored as character, its content
724 : // does not wrap around pNew
725 5376 : if (FLY_AS_CHAR == rCurrA.GetAnchorId())
726 0 : return false;
727 :
728 : // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
729 : // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
730 : // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
731 : // some more checks
732 5376 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
733 : {
734 16 : if (FLY_AT_PAGE == rCurrA.GetAnchorId())
735 : {
736 14 : bEvade = true;
737 : }
738 : else
739 2 : return false;
740 : }
741 5360 : else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
742 11 : return false; // Page anchored ones only avoid page anchored ones
743 5349 : else if (FLY_AT_FLY == rNewA.GetAnchorId())
744 0 : bEvade = true; // Non-page anchored ones avoid frame anchored ones
745 5349 : else if( FLY_AT_FLY == rCurrA.GetAnchorId() )
746 0 : return false; // Frame anchored ones do not avoid paragraph anchored ones
747 : // #i57062#
748 : // In order to avoid loop situation, it's decided to adjust
749 : // the wrapping behaviour of content of at-paragraph/at-character
750 : // anchored objects to one in the page header/footer and
751 : // the document body --> content of at-paragraph/at-character
752 : // anchored objects doesn't wrap around each other.
753 : else
754 5349 : return false;
755 : }
756 : }
757 :
758 : // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
759 : // #i68520#
760 877 : bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
761 877 : if( bEvade )
762 : {
763 : // #i68520#
764 727 : SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
765 727 : if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
766 673 : bEvade = false;
767 : }
768 : }
769 :
770 33159 : if ( bEvade )
771 : {
772 : // #i26945#
773 32336 : const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
774 : OSL_ENSURE( FLY_AS_CHAR != rNewA.GetAnchorId(),
775 : "Don't call GetTop with a FlyInCntFrm" );
776 32336 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
777 744 : return true; // We always avoid page anchored ones
778 :
779 : // If Flys anchored at paragraph are caught in a FlyCnt, then
780 : // their influence ends at the borders of the FlyCnt!
781 : // If we are currently formatting the text of the FlyCnt, then
782 : // it has to get out of the way of the Frm anchored at paragraph!
783 : // pCurrFrm is the anchor of pNew?
784 : // #i26945#
785 31592 : const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
786 31592 : if( pTmp == pCurrFrm )
787 16847 : return true;
788 14745 : if( pTmp->IsTxtFrm() && ( pTmp->IsInFly() || pTmp->IsInFtn() ) )
789 : {
790 : // #i26945#
791 33 : Point aPos = _pAnchoredObj->GetObjRect().Pos();
792 33 : pTmp = GetVirtualUpper( pTmp, aPos );
793 : }
794 : // #i26945#
795 : // #115759#
796 : // If <pTmp> is a text frame inside a table, take the upper
797 : // of the anchor frame, which contains the anchor position.
798 14712 : else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() )
799 : {
800 : pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
801 125 : ->GetAnchorFrmContainingAnchPos()->GetUpper();
802 : }
803 : // #i28701# - consider all objects in same context,
804 : // if wrapping style is considered on object positioning.
805 : // Thus, text will wrap around negative positioned objects.
806 : // #i3317# - remove condition on checking,
807 : // if wrappings style is considered on object postioning.
808 : // Thus, text is wrapping around negative positioned objects.
809 : // #i35640# - no consideration of negative
810 : // positioned objects, if wrapping style isn't considered on
811 : // object position and former text wrapping is applied.
812 : // This condition is typically for documents imported from the
813 : // OpenOffice.org file format.
814 14745 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
815 29792 : if ( ( pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
816 29490 : !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) &&
817 14745 : ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
818 : {
819 5246 : return true;
820 : }
821 :
822 9499 : const SwFrm* pHeader = 0;
823 23711 : if ( pCurrFrm->GetNext() != pTmp &&
824 18944 : ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
825 : // #i13832#, #i24135# wrap around objects in page header
826 18890 : ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
827 9180 : 0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
828 13839 : !pHeader->IsFooterFrm() &&
829 4659 : pCurrFrm->IsInDocBody() ) ) )
830 : {
831 4713 : if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
832 4659 : return true;
833 :
834 : // Compare indices:
835 : // The Index of the other is retrieved from the anchor attr.
836 54 : sal_uLong nTmpIndex = rNewA.GetCntntAnchor()->nNode.GetIndex();
837 : // Now check whether the current paragraph is before the anchor
838 : // of the displaced object in the text, then we don't have to
839 : // get out of its way.
840 : // If possible determine Index via SwFmtAnchor because
841 : // otherwise it's quite expensive.
842 54 : if( ULONG_MAX == nIndex )
843 44 : nIndex = pCurrFrm->GetNode()->GetIndex();
844 :
845 54 : if( nIndex >= nTmpIndex )
846 0 : return true;
847 : }
848 : }
849 : }
850 8383 : return false;
851 : }
852 :
853 : // #i68520#
854 24289 : SwAnchoredObjList* SwTxtFly::InitAnchoredObjList()
855 : {
856 : OSL_ENSURE( pCurrFrm, "InitFlyList: No Frame, no FlyList" );
857 : // #i68520#
858 : OSL_ENSURE( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
859 :
860 24289 : SWAP_IF_SWAPPED( pCurrFrm )
861 :
862 24289 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
863 24289 : const sal_uInt32 nCount = pSorted ? pSorted->Count() : 0;
864 : // --> #108724# Page header/footer content doesn't have to wrap around
865 : // floating screen objects
866 24289 : const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
867 24289 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
868 : // #i40155# - check, if frame is marked not to wrap
869 67859 : const bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
870 72857 : ( !pCurrFrm->IsInFtn() && !bFooterHeader ) );
871 :
872 24289 : bOn = false;
873 :
874 24289 : if( nCount && bWrapAllowed )
875 : {
876 : // #i68520#
877 19286 : mpAnchoredObjList = new SwAnchoredObjList();
878 :
879 : // #i28701# - consider complete frame area for new
880 : // text wrapping
881 19286 : SwRect aRect;
882 19286 : if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) )
883 : {
884 5 : aRect = pCurrFrm->Prt();
885 5 : aRect += pCurrFrm->Frm().Pos();
886 : }
887 : else
888 : {
889 19281 : aRect = pCurrFrm->Frm();
890 : }
891 : // Make ourselves a little smaller than we are,
892 : // so that 1-Twip-overlappings are ignored (#49532)
893 19286 : SWRECTFN( pCurrFrm )
894 19286 : const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
895 19286 : const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
896 19286 : const bool bR2L = pCurrFrm->IsRightToLeft();
897 :
898 19286 : const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess();
899 :
900 158433 : for( sal_uInt32 i = 0; i < nCount; i++ )
901 : {
902 : // #i68520#
903 : // do not consider hidden objects
904 : // check, if object has to be considered for text wrap
905 : // #118809# - If requested, do not consider
906 : // objects in page header|footer for text frames not in page
907 : // header|footer. This is requested for the calculation of
908 : // the base offset for objects <SwTxtFrm::CalcBaseOfstForFly()>
909 : // #i20505# Do not consider oversized objects
910 139147 : SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
911 : assert(pAnchoredObj);
912 695735 : if ( !pAnchoredObj ||
913 694749 : !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
914 563192 : !pAnchoredObj->ConsiderForTextWrap() ||
915 110908 : ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
916 55454 : pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
917 : {
918 110011 : continue;
919 : }
920 :
921 127042 : const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
922 341109 : if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
923 87025 : (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
924 223546 : (aBound.*fnRect->fnGetBottom)() ) > 0 ||
925 217779 : nLeft > (aBound.*fnRect->fnGetRight)() ||
926 41241 : (aBound.*fnRect->fnGetHeight)() >
927 41241 : 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
928 : {
929 85801 : continue;
930 : }
931 :
932 : // #i26945# - pass <pAnchoredObj> to method
933 : // <GetTop(..)> instead of only the <SdrObject> instance of the
934 : // anchored object
935 41241 : if ( GetTop( pAnchoredObj, pCurrFrm->IsInFtn(), bFooterHeader ) )
936 : {
937 : // OD 11.03.2003 #107862# - adjust insert position:
938 : // overlapping objects should be sorted from left to right and
939 : // inside left to right sorting from top to bottom.
940 : // If objects on the same position are found, they are sorted
941 : // on its width.
942 : // #i68520#
943 : {
944 : SwAnchoredObjList::iterator aInsPosIter =
945 : std::lower_bound( mpAnchoredObjList->begin(),
946 : mpAnchoredObjList->end(),
947 : pAnchoredObj,
948 27496 : AnchoredObjOrder( bR2L, fnRect ) );
949 :
950 27496 : mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
951 : }
952 :
953 27496 : const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
954 : // #i68520#
955 27496 : if ( rFlyFmt.IsAnchorOnly() &&
956 0 : pAnchoredObj->GetAnchorFrm() == GetMaster() )
957 : {
958 : const SwFmtVertOrient &rTmpFmt =
959 0 : pAnchoredObj->GetFrmFmt().GetVertOrient();
960 0 : if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
961 0 : nMinBottom = ( bVert && nMinBottom ) ?
962 0 : std::min( nMinBottom, aBound.Left() ) :
963 0 : std::max( nMinBottom, (aBound.*fnRect->fnGetBottom)() );
964 : }
965 :
966 27496 : bOn = true;
967 : }
968 : }
969 19286 : if( nMinBottom )
970 : {
971 0 : SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
972 0 : if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
973 0 : nMinBottom = nMax;
974 19286 : }
975 : }
976 : else
977 : {
978 : // #i68520#
979 5003 : mpAnchoredObjList = new SwAnchoredObjList();
980 : }
981 :
982 24289 : UNDO_SWAP( pCurrFrm )
983 :
984 : // #i68520#
985 24289 : return mpAnchoredObjList;
986 : }
987 :
988 21585 : SwTwips SwTxtFly::CalcMinBottom() const
989 : {
990 21585 : SwTwips nRet = 0;
991 21585 : const SwCntntFrm *pLclMaster = GetMaster();
992 : OSL_ENSURE(pLclMaster, "SwTxtFly without master");
993 21585 : const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : NULL;
994 21585 : const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0;
995 21585 : if( nCount )
996 : {
997 1013 : SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
998 2299 : for( sal_uInt32 i = 0; i < nCount; i++ )
999 : {
1000 1286 : SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
1001 1286 : const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
1002 1286 : if( rFlyFmt.IsAnchorOnly() )
1003 : {
1004 : const SwFmtVertOrient &rTmpFmt =
1005 0 : pAnchoredObj->GetFrmFmt().GetVertOrient();
1006 0 : if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
1007 : {
1008 0 : const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
1009 0 : if( aBound.Top() < nEndOfFrm )
1010 0 : nRet = std::max( nRet, aBound.Bottom() );
1011 : }
1012 : }
1013 : }
1014 1013 : SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
1015 1013 : pCurrFrm->GetUpper()->Prt().Bottom();
1016 1013 : if( nRet > nMax )
1017 0 : nRet = nMax;
1018 : }
1019 21585 : return nRet;
1020 : }
1021 :
1022 47625 : bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const
1023 : {
1024 47625 : SWAP_IF_SWAPPED( pCurrFrm )
1025 :
1026 47625 : bool bRet = false;
1027 : // #i68520#
1028 47625 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1029 47625 : if ( bOn && nCount > 0 )
1030 : {
1031 106517 : for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1032 : {
1033 : // #i68520#
1034 79992 : const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1035 :
1036 79992 : SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1037 :
1038 : // Optimierung
1039 79992 : SWRECTFN( pCurrFrm )
1040 79992 : if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
1041 4370 : break;
1042 : // #i68520#
1043 79461 : if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
1044 : {
1045 : // #i68520#
1046 21260 : const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) );
1047 21260 : const SwFmtSurround &rSur = pFmt->GetSurround();
1048 21260 : if( bAvoid )
1049 : {
1050 : // If the text flows below, it has no influence on
1051 : // formatting. In LineIter::DrawText() it is "just"
1052 : // necessary to clevely set the ClippingRegions
1053 19923 : const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
1054 57703 : if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
1055 17857 : ( !rSur.IsAnchorOnly() ||
1056 : // #i68520#
1057 0 : GetMaster() == pAnchoredObj->GetAnchorFrm() ||
1058 0 : ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
1059 0 : (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
1060 21989 : || aRect.Top() == FAR_AWAY )
1061 35809 : continue;
1062 : }
1063 :
1064 : // #i58642#
1065 : // Compare <GetMaster()> instead of <pCurrFrm> with the anchor
1066 : // frame of the anchored object, because a follow frame have
1067 : // to ignore the anchored objects of its master frame.
1068 : // Note: Anchored objects are always registered at the master
1069 : // frame, exception are as-character anchored objects,
1070 : // but these aren't handled here.
1071 : // #i68520#
1072 3542 : if ( mbIgnoreCurrentFrame &&
1073 139 : GetMaster() == pAnchoredObj->GetAnchorFrm() )
1074 71 : continue;
1075 :
1076 3332 : if( pRect )
1077 : {
1078 : // #i68520#
1079 1995 : SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
1080 1995 : if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
1081 24 : continue;
1082 3990 : if( !bRet || (
1083 48 : ( !pCurrFrm->IsRightToLeft() &&
1084 24 : ( (aFly.*fnRect->fnGetLeft)() <
1085 48 : (pRect->*fnRect->fnGetLeft)() ) ) ||
1086 24 : ( pCurrFrm->IsRightToLeft() &&
1087 0 : ( (aFly.*fnRect->fnGetRight)() >
1088 0 : (pRect->*fnRect->fnGetRight)() ) ) ) )
1089 1971 : *pRect = aFly;
1090 1995 : if( rSur.IsContour() )
1091 : {
1092 24 : bRet = true;
1093 24 : continue;
1094 : }
1095 : }
1096 3308 : bRet = true;
1097 3308 : break;
1098 : }
1099 : }
1100 : }
1101 :
1102 47625 : UNDO_SWAP( pCurrFrm )
1103 :
1104 47625 : return bRet;
1105 : }
1106 :
1107 : // #i68520#
1108 1995 : SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
1109 : {
1110 1995 : SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
1111 1995 : SwAnchoredObjList::size_type nRet = 0;
1112 4351 : while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
1113 361 : ++nRet;
1114 1995 : return nRet;
1115 : }
1116 :
1117 : // #i68520#
1118 490 : void SwTxtFly::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 : "SwTxtFly::CalcRightMargin with swapped frame" );
1125 490 : SWRECTFN( pCurrFrm )
1126 : // #118796# - correct determination of right of printing area
1127 490 : SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1128 490 : SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
1129 490 : SwRect aLine( rLine );
1130 490 : (aLine.*fnRect->fnSetRight)( nRight );
1131 490 : (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 490 : bool bStop = false;
1142 : // #i68520#
1143 490 : SwAnchoredObjList::size_type nPos = 0;
1144 :
1145 : // #i68520#
1146 1785 : while( nPos < mpAnchoredObjList->size() && !bStop )
1147 : {
1148 805 : if( nPos == nFlyPos )
1149 : {
1150 490 : ++nPos;
1151 1210 : continue;
1152 : }
1153 : // #i68520#
1154 315 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
1155 315 : if ( pNext == mpCurrAnchoredObj )
1156 0 : continue;
1157 315 : eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1158 315 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1159 230 : continue;
1160 :
1161 : const SwRect aTmp( SwContourCache::CalcBoundRect
1162 85 : ( pNext, aLine, pCurrFrm, nFlyRight, true ) );
1163 85 : 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 85 : const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
1175 85 : if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 )
1176 : {
1177 28 : if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 )
1178 9 : SetNextTop( nTmpTop ); // upper border of next frame
1179 : }
1180 57 : 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 85 : if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
1191 : {
1192 9 : nFlyRight = nTmpRight;
1193 9 : 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 490 : (rFly.*fnRect->fnSetRight)( nRight );
1204 490 : }
1205 :
1206 : // #i68520#
1207 125 : void SwTxtFly::CalcLeftMargin( SwRect &rFly,
1208 : SwAnchoredObjList::size_type nFlyPos,
1209 : const SwRect &rLine ) const
1210 : {
1211 : OSL_ENSURE( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
1212 : "SwTxtFly::CalcLeftMargin with swapped frame" );
1213 125 : SWRECTFN( pCurrFrm )
1214 : // #118796# - correct determination of left of printing area
1215 125 : SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1216 125 : const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();
1217 :
1218 125 : if( nLeft > nFlyLeft )
1219 32 : nLeft = rFly.Left();
1220 :
1221 125 : SwRect aLine( rLine );
1222 125 : (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 125 : SwAnchoredObjList::size_type nMyPos = nFlyPos;
1232 250 : while( ++nFlyPos < mpAnchoredObjList->size() )
1233 : {
1234 : // #i68520#
1235 42 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1236 42 : const SwRect aTmp( pNext->GetObjRectWithSpaces() );
1237 42 : if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
1238 42 : break;
1239 : }
1240 :
1241 384 : while( nFlyPos )
1242 : {
1243 134 : if( --nFlyPos == nMyPos )
1244 250 : continue;
1245 : // #i68520#
1246 9 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1247 9 : if( pNext == mpCurrAnchoredObj )
1248 0 : continue;
1249 9 : SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1250 9 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1251 0 : continue;
1252 :
1253 : const SwRect aTmp( SwContourCache::CalcBoundRect
1254 9 : ( pNext, aLine, pCurrFrm, nFlyLeft, false ) );
1255 :
1256 9 : 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 125 : (rFly.*fnRect->fnSetLeft)( nLeft );
1268 125 : }
1269 :
1270 : // #i68520#
1271 1995 : SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
1272 : const SwRect &rLine ) const
1273 : {
1274 1995 : SWRECTFN( pCurrFrm )
1275 :
1276 1995 : const long nXPos = pCurrFrm->IsRightToLeft() ?
1277 : rLine.Right() :
1278 1995 : (rLine.*fnRect->fnGetLeft)();
1279 :
1280 : SwRect aFly = mbIgnoreContour ?
1281 206 : pAnchoredObj->GetObjRectWithSpaces() :
1282 : SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
1283 2201 : nXPos, ! pCurrFrm->IsRightToLeft() );
1284 :
1285 1995 : if( !aFly.Width() )
1286 0 : return aFly;
1287 :
1288 : // so the line may grow up to the lower edge of the frame
1289 1995 : SetNextTop( (aFly.*fnRect->fnGetBottom)() );
1290 1995 : 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 1995 : switch( _GetSurroundForTextWrap( pAnchoredObj ) )
1302 : {
1303 : case SURROUND_LEFT :
1304 : {
1305 388 : CalcRightMargin( aFly, nFlyPos, rLine );
1306 388 : break;
1307 : }
1308 : case SURROUND_RIGHT :
1309 : {
1310 23 : CalcLeftMargin( aFly, nFlyPos, rLine );
1311 23 : break;
1312 : }
1313 : case SURROUND_NONE :
1314 : {
1315 102 : CalcRightMargin( aFly, nFlyPos, rLine );
1316 102 : CalcLeftMargin( aFly, nFlyPos, rLine );
1317 102 : break;
1318 : }
1319 : default:
1320 1482 : break;
1321 : }
1322 1995 : 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 2319 : SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
1337 : {
1338 2319 : const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
1339 2319 : const SwFmtSurround &rFlyFmt = pFmt->GetSurround();
1340 2319 : SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround();
1341 :
1342 2319 : if( rFlyFmt.IsAnchorOnly() && pAnchoredObj->GetAnchorFrm() != GetMaster() )
1343 : {
1344 0 : const SwFmtAnchor& rAnchor = pFmt->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 2319 : if( SURROUND_THROUGHT == eSurroundForTextWrap ||
1354 : SURROUND_NONE == eSurroundForTextWrap )
1355 323 : return eSurroundForTextWrap;
1356 :
1357 : // left is left and right is right
1358 1996 : 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 1996 : if ( SURROUND_IDEAL == eSurroundForTextWrap )
1368 : {
1369 511 : SWRECTFN( pCurrFrm )
1370 511 : const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1371 511 : const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1372 511 : const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1373 511 : long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
1374 511 : long nFlyRight = (aRect.*fnRect->fnGetRight)();
1375 :
1376 511 : if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
1377 0 : eSurroundForTextWrap = SURROUND_PARALLEL;
1378 : else
1379 : {
1380 511 : long nLeft = nFlyLeft - nCurrLeft;
1381 511 : long nRight = nCurrRight - nFlyRight;
1382 511 : if( nFlyRight - nFlyLeft > FRAME_MAX )
1383 : {
1384 416 : if( nLeft < nRight )
1385 28 : nLeft = 0;
1386 : else
1387 388 : nRight = 0;
1388 : }
1389 511 : const int textMin = GetMaster()->GetNode()
1390 511 : ->getIDocumentSettingAccess()->get(IDocumentSettingAccess::SURROUND_TEXT_WRAP_SMALL )
1391 511 : ? TEXT_MIN_SMALL : TEXT_MIN;
1392 511 : if( nLeft < textMin )
1393 81 : nLeft = 0;
1394 511 : if( nRight < textMin )
1395 449 : nRight = 0;
1396 511 : if( nLeft )
1397 430 : eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
1398 : else
1399 81 : eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
1400 : }
1401 : }
1402 :
1403 1996 : return eSurroundForTextWrap;
1404 : }
1405 :
1406 0 : bool SwTxtFly::IsAnyFrm( const SwRect &rLine ) const
1407 : {
1408 :
1409 0 : SWAP_IF_SWAPPED( pCurrFrm )
1410 :
1411 : OSL_ENSURE( bOn, "IsAnyFrm: Why?" );
1412 :
1413 0 : const bool bRet = ForEach( rLine, NULL, false );
1414 0 : UNDO_SWAP( pCurrFrm )
1415 0 : return bRet;
1416 : }
1417 :
1418 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|