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 0 : AnchoredObjOrder( const bool bR2L,
74 : SwRectFn fnRect )
75 : : mbR2L( bR2L ),
76 0 : mfnRect( fnRect )
77 0 : {}
78 :
79 0 : bool operator()( const SwAnchoredObject* pListedAnchoredObj,
80 : const SwAnchoredObject* pNewAnchoredObj )
81 : {
82 0 : const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
83 0 : const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
84 0 : if ( ( mbR2L &&
85 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
86 0 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
87 0 : ( !mbR2L &&
88 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
89 0 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
90 : {
91 : SwTwips nTopDiff =
92 0 : (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
93 0 : (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
94 0 : if ( nTopDiff == 0 &&
95 0 : ( ( mbR2L &&
96 0 : ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
97 0 : (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
98 0 : ( !mbR2L &&
99 0 : ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
100 0 : (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
101 : {
102 0 : return true;
103 : }
104 0 : else if ( nTopDiff > 0 )
105 : {
106 0 : return true;
107 : }
108 : }
109 0 : else if ( ( mbR2L &&
110 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
111 0 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
112 0 : ( !mbR2L &&
113 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
114 0 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
115 : {
116 0 : return true;
117 : }
118 :
119 0 : return false;
120 : }
121 : };
122 : }
123 :
124 0 : SwContourCache::SwContourCache() :
125 0 : nPntCnt( 0 ), nObjCnt( 0 )
126 : {
127 0 : memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) );
128 0 : memset( pTextRanger, 0, sizeof(pTextRanger) );
129 0 : }
130 :
131 0 : SwContourCache::~SwContourCache()
132 : {
133 0 : for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
134 : ;
135 0 : }
136 :
137 0 : void SwContourCache::ClrObject( MSHORT nPos )
138 : {
139 : OSL_ENSURE( pTextRanger[ nPos ], "ClrObject: Already cleared. Good Bye!" );
140 0 : nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
141 0 : delete pTextRanger[ nPos ];
142 0 : --nObjCnt;
143 0 : memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1,
144 0 : ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
145 0 : memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
146 0 : ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
147 0 : }
148 :
149 0 : void ClrContourCache( const SdrObject *pObj )
150 : {
151 0 : if( pContourCache && pObj )
152 0 : for( MSHORT i = 0; i < pContourCache->GetCount(); ++i )
153 0 : if( pObj == pContourCache->GetObject( i ) )
154 : {
155 0 : pContourCache->ClrObject( i );
156 0 : break;
157 : }
158 0 : }
159 :
160 0 : void ClrContourCache()
161 : {
162 0 : if( pContourCache )
163 : {
164 0 : for( MSHORT i = 0; i < pContourCache->GetCount();
165 0 : delete pContourCache->pTextRanger[ i++ ] )
166 : ;
167 0 : pContourCache->nObjCnt = 0;
168 0 : pContourCache->nPntCnt = 0;
169 : }
170 0 : }
171 :
172 : // #i68520#
173 0 : 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 0 : SwRect aRet;
180 0 : const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
181 0 : if( pFmt->GetSurround().IsContour() &&
182 0 : ( !pAnchoredObj->ISA(SwFlyFrm) ||
183 0 : ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
184 0 : static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) )
185 : {
186 0 : aRet = pAnchoredObj->GetObjRectWithSpaces();
187 0 : if( aRet.IsOver( rLine ) )
188 : {
189 0 : if( !pContourCache )
190 0 : pContourCache = new SwContourCache;
191 :
192 0 : aRet = pContourCache->ContourRect(
193 0 : pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
194 : }
195 : else
196 0 : aRet.Width( 0 );
197 : }
198 : else
199 : {
200 0 : aRet = pAnchoredObj->GetObjRectWithSpaces();
201 : }
202 :
203 0 : return aRet;
204 : }
205 :
206 0 : 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 0 : SwRect aRet;
211 0 : MSHORT nPos = 0; // Suche im Cache ...
212 0 : while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
213 0 : ++nPos;
214 0 : if( GetCount() == nPos ) // nicht gefunden
215 : {
216 0 : if( nObjCnt == POLY_CNT )
217 : {
218 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
219 0 : delete pTextRanger[ nObjCnt ];
220 : }
221 0 : ::basegfx::B2DPolyPolygon aPolyPolygon;
222 0 : ::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;
223 :
224 0 : 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 0 : PolyPolygon aPoly;
229 0 : if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) )
230 0 : aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)->
231 0 : GetFlyFrm()->Frm().SVRect() );
232 0 : aPolyPolygon.clear();
233 0 : 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 0 : const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace();
246 0 : const SvxULSpaceItem &rULSpace = pFmt->GetULSpace();
247 0 : memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
248 0 : memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
249 0 : pSdrObj[ 0 ] = pObj; // due to #37347 the Object must be entered only
250 : // after GetContour()
251 : pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
252 0 : (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(),
253 0 : pFmt->GetSurround().IsOutside(), false, pFrm->IsVertical() );
254 0 : pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
255 0 : pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );
256 :
257 0 : delete pPolyPolygon;
258 :
259 0 : nPntCnt += pTextRanger[ 0 ]->GetPointCount();
260 0 : while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
261 : {
262 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
263 0 : delete pTextRanger[ nObjCnt ];
264 0 : }
265 : }
266 0 : 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 0 : SWRECTFN( pFrm )
276 0 : long nTmpTop = (rLine.*fnRect->fnGetTop)();
277 : // fnGetBottom is top + height
278 0 : long nTmpBottom = (rLine.*fnRect->fnGetBottom)();
279 :
280 0 : Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );
281 :
282 0 : LongDqPtr pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );
283 :
284 : MSHORT nCount;
285 0 : if( 0 != ( nCount = pTmp->size() ) )
286 : {
287 0 : MSHORT nIdx = 0;
288 0 : while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
289 0 : ++nIdx;
290 0 : bool bOdd = (nIdx % 2);
291 0 : bool bSet = true;
292 0 : if( bOdd )
293 0 : --nIdx; // within interval
294 0 : 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 0 : if( bSet && nIdx < nCount )
303 : {
304 0 : (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
305 0 : (rLine.*fnRect->fnGetHeight)() );
306 0 : (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
307 0 : (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
308 : }
309 : }
310 0 : return aRet;
311 : }
312 :
313 0 : SwTxtFly::SwTxtFly() :
314 : pPage(0),
315 : mpCurrAnchoredObj(0),
316 : pCurrFrm(0),
317 : pMaster(0),
318 : mpAnchoredObjList(0),
319 : nMinBottom(0),
320 : nNextTop(0),
321 0 : nIndex(0)
322 : {
323 0 : }
324 :
325 0 : SwTxtFly::SwTxtFly( const SwTxtFrm *pFrm )
326 : {
327 0 : CtorInitTxtFly( pFrm );
328 0 : }
329 :
330 0 : SwTxtFly::SwTxtFly( const SwTxtFly& rTxtFly )
331 : {
332 0 : pPage = rTxtFly.pPage;
333 0 : mpCurrAnchoredObj = rTxtFly.mpCurrAnchoredObj;
334 0 : pCurrFrm = rTxtFly.pCurrFrm;
335 0 : pMaster = rTxtFly.pMaster;
336 0 : if( rTxtFly.mpAnchoredObjList )
337 : {
338 0 : mpAnchoredObjList = new SwAnchoredObjList( *(rTxtFly.mpAnchoredObjList) );
339 : }
340 : else
341 : {
342 0 : mpAnchoredObjList = NULL;
343 : }
344 :
345 0 : bOn = rTxtFly.bOn;
346 0 : bTopRule = rTxtFly.bTopRule;
347 0 : nMinBottom = rTxtFly.nMinBottom;
348 0 : nNextTop = rTxtFly.nNextTop;
349 0 : nIndex = rTxtFly.nIndex;
350 0 : mbIgnoreCurrentFrame = rTxtFly.mbIgnoreCurrentFrame;
351 0 : mbIgnoreContour = rTxtFly.mbIgnoreContour;
352 0 : mbIgnoreObjsInHeaderFooter = rTxtFly.mbIgnoreObjsInHeaderFooter;
353 0 : }
354 :
355 0 : SwTxtFly::~SwTxtFly()
356 : {
357 0 : delete mpAnchoredObjList;
358 0 : }
359 :
360 0 : void SwTxtFly::CtorInitTxtFly( const SwTxtFrm *pFrm )
361 : {
362 0 : mbIgnoreCurrentFrame = false;
363 0 : mbIgnoreContour = false;
364 : // #118809#
365 0 : mbIgnoreObjsInHeaderFooter = false;
366 0 : pPage = pFrm->FindPageFrm();
367 0 : const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
368 : // #i68520#
369 0 : mpCurrAnchoredObj = pTmp;
370 0 : pCurrFrm = pFrm;
371 0 : pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
372 : // #i68520#
373 0 : 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 0 : bOn = pPage->GetSortedObjs() != 0;
380 0 : bTopRule = true;
381 0 : nMinBottom = 0;
382 0 : nNextTop = 0;
383 0 : nIndex = ULONG_MAX;
384 0 : }
385 :
386 0 : SwRect SwTxtFly::_GetFrm( const SwRect &rRect, bool bTop ) const
387 : {
388 0 : SwRect aRet;
389 0 : if( ForEach( rRect, &aRet, true ) )
390 : {
391 0 : SWRECTFN( pCurrFrm )
392 0 : if( bTop )
393 0 : (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );
394 :
395 : // 8110: Do not always adapt the bottom
396 0 : const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
397 0 : const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
398 0 : if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
399 0 : (aRet.*fnRect->fnGetHeight)() < 0 )
400 0 : (aRet.*fnRect->fnSetBottom)( nRectBottom );
401 : }
402 0 : return aRet;
403 : }
404 :
405 0 : bool SwTxtFly::IsAnyFrm() const
406 : {
407 0 : SWAP_IF_SWAPPED( pCurrFrm )
408 :
409 : OSL_ENSURE( bOn, "IsAnyFrm: Why?" );
410 0 : SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
411 0 : pCurrFrm->Prt().SSize() );
412 :
413 0 : const bool bRet = ForEach( aRect, NULL, false );
414 0 : UNDO_SWAP( pCurrFrm )
415 0 : return bRet;
416 : }
417 :
418 0 : bool SwTxtFly::IsAnyObj( const SwRect &rRect ) const
419 : {
420 : OSL_ENSURE( bOn, "SwTxtFly::IsAnyObj: Who's knocking?" );
421 :
422 0 : SwRect aRect( rRect );
423 0 : if ( aRect.IsEmpty() )
424 0 : aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
425 0 : pCurrFrm->Prt().SSize() );
426 :
427 0 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
428 0 : 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 0 : for ( MSHORT i = 0; i < pSorted->Count(); ++i )
432 : {
433 0 : const SwAnchoredObject* pObj = (*pSorted)[i];
434 :
435 0 : const SwRect aBound( pObj->GetObjRectWithSpaces() );
436 :
437 : // Optimization
438 0 : if( pObj->GetObjRect().Left() > aRect.Right() )
439 0 : continue;
440 :
441 : // #i68520#
442 0 : if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
443 0 : return true;
444 : }
445 : }
446 0 : return false;
447 : }
448 :
449 0 : const SwCntntFrm* SwTxtFly::_GetMaster()
450 : {
451 0 : pMaster = pCurrFrm;
452 0 : while( pMaster && pMaster->IsFollow() )
453 0 : pMaster = (SwCntntFrm*)pMaster->FindMaster();
454 0 : return pMaster;
455 : }
456 :
457 0 : bool SwTxtFly::DrawTextOpaque( SwDrawTextInfo &rInf )
458 : {
459 0 : SwSaveClip aClipSave( rInf.GetpOut() );
460 0 : SwRect aRect( rInf.GetPos(), rInf.GetSize() );
461 0 : if( rInf.GetSpace() )
462 : {
463 0 : sal_Int32 nTmpLen = COMPLETE_STRING == rInf.GetLen() ? rInf.GetText().getLength() :
464 0 : rInf.GetLen();
465 0 : if( rInf.GetSpace() > 0 )
466 : {
467 0 : sal_Int32 nSpaceCnt = 0;
468 0 : const sal_Int32 nEndPos = rInf.GetIdx() + nTmpLen;
469 0 : for( sal_Int32 nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos )
470 : {
471 0 : if( CH_BLANK == rInf.GetText()[ nPos ] )
472 0 : ++nSpaceCnt;
473 : }
474 0 : if( nSpaceCnt )
475 0 : aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
476 : }
477 : else
478 0 : aRect.Width( aRect.Width() - nTmpLen * rInf.GetSpace() );
479 : }
480 :
481 0 : if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
482 : {
483 0 : SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
484 0 : aRect.Intersection( aClipRect );
485 : }
486 :
487 0 : SwRegionRects aRegion( aRect );
488 :
489 0 : bool bOpaque = false;
490 : // #i68520#
491 : const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
492 0 : ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
493 0 : : SAL_MAX_UINT32;
494 : OSL_ENSURE( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
495 :
496 : // #i68520#
497 0 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
498 0 : if ( bOn && nCount > 0 )
499 : {
500 0 : MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
501 0 : for( MSHORT i = 0; i < nCount; ++i )
502 : {
503 : // #i68520#
504 0 : const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
505 0 : if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
506 0 : mpCurrAnchoredObj != pTmpAnchoredObj )
507 : {
508 : // #i68520#
509 0 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj);
510 0 : if( aRegion.GetOrigin().IsOver( pFly->Frm() ) )
511 : {
512 0 : const SwFrmFmt *pFmt = pFly->GetFmt();
513 0 : const SwFmtSurround &rSur = pFmt->GetSurround();
514 0 : const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
515 : // Only the ones who are opaque and more to the top
516 0 : if( !( pFly->IsBackgroundTransparent()
517 0 : || pFly->IsShadowTransparent() ) &&
518 0 : SURROUND_THROUGHT == rSur.GetSurround() &&
519 0 : ( !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 0 : ) &&
526 : // #i68520#
527 0 : 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 0 : Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
549 0 : const Point aOldPos(rInf.GetPos());
550 0 : rInf.SetPos( aPos );
551 :
552 0 : if( !bOpaque )
553 : {
554 0 : if( rInf.GetKern() )
555 0 : rInf.GetFont()->_DrawStretchText( rInf );
556 : else
557 0 : rInf.GetFont()->_DrawText( rInf );
558 0 : rInf.SetPos(aOldPos);
559 0 : 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 0 : return true;
578 : }
579 :
580 0 : void SwTxtFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
581 : const SwTxtPaintInfo &rInf, bool bNoGraphic )
582 : {
583 0 : SwRegionRects aRegion( rRect );
584 : OSL_ENSURE( !bTopRule, "DrawFlyRect: Wrong TopRule" );
585 : // #i68520#
586 0 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
587 0 : if ( bOn && nCount > 0 )
588 : {
589 0 : MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
590 0 : for( MSHORT i = 0; i < nCount; ++i )
591 : {
592 : // #i68520#
593 0 : const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
594 0 : if (mpCurrAnchoredObj == pAnchoredObjTmp)
595 0 : continue;
596 :
597 : // #i68520#
598 0 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
599 0 : if (pFly)
600 : {
601 : // #i68520#
602 0 : 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 0 : ( ( SURROUND_THROUGHT == rSur.GetSurround() )
611 : // #i68520#
612 0 : ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
613 0 : : !rSur.IsContour() ) &&
614 0 : !pFly->IsBackgroundTransparent() &&
615 0 : !pFly->IsShadowTransparent() &&
616 0 : ( !pFly->Lower() ||
617 0 : !pFly->Lower()->IsNoTxtFrm() ||
618 0 : !static_cast<const SwNoTxtFrm*>(pFly->Lower())->IsTransparent() );
619 0 : if ( bClipFlyArea )
620 : {
621 : // #i68520#
622 0 : SwRect aFly( pAnchoredObjTmp->GetObjRect() );
623 : // OD 24.01.2003 #106593#
624 0 : ::SwAlignRect( aFly, pPage->getRootFrm()->GetCurrShell() );
625 0 : if( aFly.Width() > 0 && aFly.Height() > 0 )
626 0 : aRegion -= aFly;
627 : }
628 : }
629 : }
630 : }
631 :
632 0 : for( MSHORT i = 0; i < aRegion.size(); ++i )
633 : {
634 0 : if ( bNoGraphic )
635 : {
636 0 : 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 0 : }
650 0 : }
651 :
652 : // #i26945# - change first parameter
653 : // Now it's the <SwAnchoredObject> instance of the floating screen object
654 0 : 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 0 : if( _pAnchoredObj != mpCurrAnchoredObj )
661 : {
662 : // #i26945#
663 0 : const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
664 : // #102344# Ignore connectors which have one or more connections
665 0 : 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 0 : 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 0 : bool bEvade = !mpCurrAnchoredObj ||
699 0 : Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);
700 :
701 0 : 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 0 : if ( !bTopRule )
710 0 : bEvade = true;
711 : else
712 : {
713 : // Within chained Flys we only avoid Lower
714 : // #i68520#
715 0 : const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain();
716 0 : if ( !rChain.GetPrev() && !rChain.GetNext() )
717 : {
718 : // #i26945#
719 0 : const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
720 : // #i68520#
721 0 : const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor();
722 :
723 : // If <mpCurrAnchoredObj> is anchored as character, its content
724 : // does not wrap around pNew
725 0 : 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 0 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
733 : {
734 0 : if (FLY_AT_PAGE == rCurrA.GetAnchorId())
735 : {
736 0 : bEvade = true;
737 : }
738 : else
739 0 : return false;
740 : }
741 0 : else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
742 0 : return false; // Page anchored ones only avoid page anchored ones
743 0 : else if (FLY_AT_FLY == rNewA.GetAnchorId())
744 0 : bEvade = true; // Non-page anchored ones avoid frame anchored ones
745 0 : 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 0 : return false;
755 : }
756 : }
757 :
758 : // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
759 : // #i68520#
760 0 : bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
761 0 : if( bEvade )
762 : {
763 : // #i68520#
764 0 : SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
765 0 : if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
766 0 : bEvade = false;
767 : }
768 : }
769 :
770 0 : if ( bEvade )
771 : {
772 : // #i26945#
773 0 : const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
774 : OSL_ENSURE( FLY_AS_CHAR != rNewA.GetAnchorId(),
775 : "Don't call GetTop with a FlyInCntFrm" );
776 0 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
777 0 : 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 0 : const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
786 0 : if( pTmp == pCurrFrm )
787 0 : return true;
788 0 : if( pTmp->IsTxtFrm() && ( pTmp->IsInFly() || pTmp->IsInFtn() ) )
789 : {
790 : // #i26945#
791 0 : Point aPos = _pAnchoredObj->GetObjRect().Pos();
792 0 : 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 0 : else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() )
799 : {
800 : pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
801 0 : ->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 0 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
815 0 : if ( ( pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
816 0 : !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) &&
817 0 : ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
818 : {
819 0 : return true;
820 : }
821 :
822 0 : const SwFrm* pHeader = 0;
823 0 : if ( pCurrFrm->GetNext() != pTmp &&
824 0 : ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
825 : // #i13832#, #i24135# wrap around objects in page header
826 0 : ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
827 0 : 0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
828 0 : !pHeader->IsFooterFrm() &&
829 0 : pCurrFrm->IsInDocBody() ) ) )
830 : {
831 0 : if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
832 0 : return true;
833 :
834 : // Compare indices:
835 : // The Index of the other is retrieved from the anchor attr.
836 0 : 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 0 : if( ULONG_MAX == nIndex )
843 0 : nIndex = pCurrFrm->GetNode()->GetIndex();
844 :
845 0 : if( nIndex >= nTmpIndex )
846 0 : return true;
847 : }
848 : }
849 : }
850 0 : return false;
851 : }
852 :
853 : // #i68520#
854 0 : 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 0 : SWAP_IF_SWAPPED( pCurrFrm )
861 :
862 0 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
863 0 : 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 0 : const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
867 0 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
868 : // #i40155# - check, if frame is marked not to wrap
869 0 : const bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
870 0 : ( !pCurrFrm->IsInFtn() && !bFooterHeader ) );
871 :
872 0 : bOn = false;
873 :
874 0 : if( nCount && bWrapAllowed )
875 : {
876 : // #i68520#
877 0 : mpAnchoredObjList = new SwAnchoredObjList();
878 :
879 : // #i28701# - consider complete frame area for new
880 : // text wrapping
881 0 : SwRect aRect;
882 0 : if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) )
883 : {
884 0 : aRect = pCurrFrm->Prt();
885 0 : aRect += pCurrFrm->Frm().Pos();
886 : }
887 : else
888 : {
889 0 : aRect = pCurrFrm->Frm();
890 : }
891 : // Make ourselves a little smaller than we are,
892 : // so that 1-Twip-overlappings are ignored (#49532)
893 0 : SWRECTFN( pCurrFrm )
894 0 : const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
895 0 : const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
896 0 : const bool bR2L = pCurrFrm->IsRightToLeft();
897 :
898 0 : const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess();
899 :
900 0 : 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 0 : SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
911 : assert(pAnchoredObj);
912 0 : if ( !pAnchoredObj ||
913 0 : !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
914 0 : !pAnchoredObj->ConsiderForTextWrap() ||
915 0 : ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
916 0 : pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
917 : {
918 0 : continue;
919 : }
920 :
921 0 : const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
922 0 : if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
923 0 : (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
924 0 : (aBound.*fnRect->fnGetBottom)() ) > 0 ||
925 0 : nLeft > (aBound.*fnRect->fnGetRight)() ||
926 0 : (aBound.*fnRect->fnGetHeight)() >
927 0 : 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
928 : {
929 0 : continue;
930 : }
931 :
932 : // #i26945# - pass <pAnchoredObj> to method
933 : // <GetTop(..)> instead of only the <SdrObject> instance of the
934 : // anchored object
935 0 : 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 0 : AnchoredObjOrder( bR2L, fnRect ) );
949 :
950 0 : mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
951 : }
952 :
953 0 : const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
954 : // #i68520#
955 0 : 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 0 : bOn = true;
967 : }
968 : }
969 0 : if( nMinBottom )
970 : {
971 0 : SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
972 0 : if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
973 0 : nMinBottom = nMax;
974 0 : }
975 : }
976 : else
977 : {
978 : // #i68520#
979 0 : mpAnchoredObjList = new SwAnchoredObjList();
980 : }
981 :
982 0 : UNDO_SWAP( pCurrFrm )
983 :
984 : // #i68520#
985 0 : return mpAnchoredObjList;
986 : }
987 :
988 0 : SwTwips SwTxtFly::CalcMinBottom() const
989 : {
990 0 : SwTwips nRet = 0;
991 0 : const SwCntntFrm *pLclMaster = GetMaster();
992 : OSL_ENSURE(pLclMaster, "SwTxtFly without master");
993 0 : const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : NULL;
994 0 : const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0;
995 0 : if( nCount )
996 : {
997 0 : SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
998 0 : for( sal_uInt32 i = 0; i < nCount; i++ )
999 : {
1000 0 : SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
1001 0 : const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
1002 0 : 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 0 : SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
1015 0 : pCurrFrm->GetUpper()->Prt().Bottom();
1016 0 : if( nRet > nMax )
1017 0 : nRet = nMax;
1018 : }
1019 0 : return nRet;
1020 : }
1021 :
1022 0 : bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const
1023 : {
1024 0 : SWAP_IF_SWAPPED( pCurrFrm )
1025 :
1026 0 : bool bRet = false;
1027 : // #i68520#
1028 0 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1029 0 : if ( bOn && nCount > 0 )
1030 : {
1031 0 : for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1032 : {
1033 : // #i68520#
1034 0 : const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1035 :
1036 0 : SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1037 :
1038 : // Optimierung
1039 0 : SWRECTFN( pCurrFrm )
1040 0 : if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
1041 0 : break;
1042 : // #i68520#
1043 0 : if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
1044 : {
1045 : // #i68520#
1046 0 : const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) );
1047 0 : const SwFmtSurround &rSur = pFmt->GetSurround();
1048 0 : 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 0 : const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
1054 0 : if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
1055 0 : ( !rSur.IsAnchorOnly() ||
1056 : // #i68520#
1057 0 : GetMaster() == pAnchoredObj->GetAnchorFrm() ||
1058 0 : ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
1059 0 : (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
1060 0 : || aRect.Top() == FAR_AWAY )
1061 0 : 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 0 : if ( mbIgnoreCurrentFrame &&
1073 0 : GetMaster() == pAnchoredObj->GetAnchorFrm() )
1074 0 : continue;
1075 :
1076 0 : if( pRect )
1077 : {
1078 : // #i68520#
1079 0 : SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
1080 0 : if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
1081 0 : continue;
1082 0 : if( !bRet || (
1083 0 : ( !pCurrFrm->IsRightToLeft() &&
1084 0 : ( (aFly.*fnRect->fnGetLeft)() <
1085 0 : (pRect->*fnRect->fnGetLeft)() ) ) ||
1086 0 : ( pCurrFrm->IsRightToLeft() &&
1087 0 : ( (aFly.*fnRect->fnGetRight)() >
1088 0 : (pRect->*fnRect->fnGetRight)() ) ) ) )
1089 0 : *pRect = aFly;
1090 0 : if( rSur.IsContour() )
1091 : {
1092 0 : bRet = true;
1093 0 : continue;
1094 : }
1095 : }
1096 0 : bRet = true;
1097 0 : break;
1098 : }
1099 : }
1100 : }
1101 :
1102 0 : UNDO_SWAP( pCurrFrm )
1103 :
1104 0 : return bRet;
1105 : }
1106 :
1107 : // #i68520#
1108 0 : SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
1109 : {
1110 0 : SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
1111 0 : SwAnchoredObjList::size_type nRet = 0;
1112 0 : while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
1113 0 : ++nRet;
1114 0 : return nRet;
1115 : }
1116 :
1117 : // #i68520#
1118 0 : 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 0 : SWRECTFN( pCurrFrm )
1126 : // #118796# - correct determination of right of printing area
1127 0 : SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1128 0 : SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
1129 0 : SwRect aLine( rLine );
1130 0 : (aLine.*fnRect->fnSetRight)( nRight );
1131 0 : (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 0 : bool bStop = false;
1142 : // #i68520#
1143 0 : SwAnchoredObjList::size_type nPos = 0;
1144 :
1145 : // #i68520#
1146 0 : while( nPos < mpAnchoredObjList->size() && !bStop )
1147 : {
1148 0 : if( nPos == nFlyPos )
1149 : {
1150 0 : ++nPos;
1151 0 : continue;
1152 : }
1153 : // #i68520#
1154 0 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
1155 0 : if ( pNext == mpCurrAnchoredObj )
1156 0 : continue;
1157 0 : eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1158 0 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1159 0 : continue;
1160 :
1161 : const SwRect aTmp( SwContourCache::CalcBoundRect
1162 0 : ( pNext, aLine, pCurrFrm, nFlyRight, true ) );
1163 0 : 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 0 : const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
1175 0 : if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 )
1176 : {
1177 0 : if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 )
1178 0 : SetNextTop( nTmpTop ); // upper border of next frame
1179 : }
1180 0 : 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 0 : if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
1191 : {
1192 0 : nFlyRight = nTmpRight;
1193 0 : 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 0 : (rFly.*fnRect->fnSetRight)( nRight );
1204 0 : }
1205 :
1206 : // #i68520#
1207 0 : 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 0 : SWRECTFN( pCurrFrm )
1214 : // #118796# - correct determination of left of printing area
1215 0 : SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1216 0 : const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();
1217 :
1218 0 : if( nLeft > nFlyLeft )
1219 0 : nLeft = rFly.Left();
1220 :
1221 0 : SwRect aLine( rLine );
1222 0 : (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 0 : SwAnchoredObjList::size_type nMyPos = nFlyPos;
1232 0 : while( ++nFlyPos < mpAnchoredObjList->size() )
1233 : {
1234 : // #i68520#
1235 0 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1236 0 : const SwRect aTmp( pNext->GetObjRectWithSpaces() );
1237 0 : if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
1238 0 : break;
1239 : }
1240 :
1241 0 : while( nFlyPos )
1242 : {
1243 0 : if( --nFlyPos == nMyPos )
1244 0 : continue;
1245 : // #i68520#
1246 0 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1247 0 : if( pNext == mpCurrAnchoredObj )
1248 0 : continue;
1249 0 : SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1250 0 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1251 0 : continue;
1252 :
1253 : const SwRect aTmp( SwContourCache::CalcBoundRect
1254 0 : ( pNext, aLine, pCurrFrm, nFlyLeft, false ) );
1255 :
1256 0 : 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 0 : (rFly.*fnRect->fnSetLeft)( nLeft );
1268 0 : }
1269 :
1270 : // #i68520#
1271 0 : SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
1272 : const SwRect &rLine ) const
1273 : {
1274 0 : SWRECTFN( pCurrFrm )
1275 :
1276 0 : const long nXPos = pCurrFrm->IsRightToLeft() ?
1277 : rLine.Right() :
1278 0 : (rLine.*fnRect->fnGetLeft)();
1279 :
1280 : SwRect aFly = mbIgnoreContour ?
1281 0 : pAnchoredObj->GetObjRectWithSpaces() :
1282 : SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
1283 0 : nXPos, ! pCurrFrm->IsRightToLeft() );
1284 :
1285 0 : if( !aFly.Width() )
1286 0 : return aFly;
1287 :
1288 : // so the line may grow up to the lower edge of the frame
1289 0 : SetNextTop( (aFly.*fnRect->fnGetBottom)() );
1290 0 : 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 0 : switch( _GetSurroundForTextWrap( pAnchoredObj ) )
1302 : {
1303 : case SURROUND_LEFT :
1304 : {
1305 0 : CalcRightMargin( aFly, nFlyPos, rLine );
1306 0 : break;
1307 : }
1308 : case SURROUND_RIGHT :
1309 : {
1310 0 : CalcLeftMargin( aFly, nFlyPos, rLine );
1311 0 : break;
1312 : }
1313 : case SURROUND_NONE :
1314 : {
1315 0 : CalcRightMargin( aFly, nFlyPos, rLine );
1316 0 : CalcLeftMargin( aFly, nFlyPos, rLine );
1317 0 : break;
1318 : }
1319 : default:
1320 0 : break;
1321 : }
1322 0 : 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 0 : SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
1337 : {
1338 0 : const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
1339 0 : const SwFmtSurround &rFlyFmt = pFmt->GetSurround();
1340 0 : SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround();
1341 :
1342 0 : 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 0 : if( SURROUND_THROUGHT == eSurroundForTextWrap ||
1354 : SURROUND_NONE == eSurroundForTextWrap )
1355 0 : return eSurroundForTextWrap;
1356 :
1357 : // left is left and right is right
1358 0 : 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 0 : if ( SURROUND_IDEAL == eSurroundForTextWrap )
1368 : {
1369 0 : SWRECTFN( pCurrFrm )
1370 0 : const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1371 0 : const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1372 0 : const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1373 0 : long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
1374 0 : long nFlyRight = (aRect.*fnRect->fnGetRight)();
1375 :
1376 0 : if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
1377 0 : eSurroundForTextWrap = SURROUND_PARALLEL;
1378 : else
1379 : {
1380 0 : long nLeft = nFlyLeft - nCurrLeft;
1381 0 : long nRight = nCurrRight - nFlyRight;
1382 0 : if( nFlyRight - nFlyLeft > FRAME_MAX )
1383 : {
1384 0 : if( nLeft < nRight )
1385 0 : nLeft = 0;
1386 : else
1387 0 : nRight = 0;
1388 : }
1389 0 : const int textMin = GetMaster()->GetNode()
1390 0 : ->getIDocumentSettingAccess()->get(IDocumentSettingAccess::SURROUND_TEXT_WRAP_SMALL )
1391 0 : ? TEXT_MIN_SMALL : TEXT_MIN;
1392 0 : if( nLeft < textMin )
1393 0 : nLeft = 0;
1394 0 : if( nRight < textMin )
1395 0 : nRight = 0;
1396 0 : if( nLeft )
1397 0 : eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
1398 : else
1399 0 : eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
1400 : }
1401 : }
1402 :
1403 0 : 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: */
|