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