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 788 : AnchoredObjOrder( const sal_Bool bR2L,
76 : SwRectFn fnRect )
77 : : mbR2L( bR2L ),
78 788 : mfnRect( fnRect )
79 788 : {}
80 :
81 133 : bool operator()( const SwAnchoredObject* pListedAnchoredObj,
82 : const SwAnchoredObject* pNewAnchoredObj )
83 : {
84 133 : const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
85 133 : const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
86 133 : if ( ( mbR2L &&
87 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
88 298 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
89 266 : ( !mbR2L &&
90 133 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
91 133 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
92 : {
93 : SwTwips nTopDiff =
94 32 : (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
95 64 : (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
96 32 : if ( nTopDiff == 0 &&
97 0 : ( ( mbR2L &&
98 0 : ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
99 26 : (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
100 52 : ( !mbR2L &&
101 26 : ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
102 26 : (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
103 : {
104 0 : return true;
105 : }
106 32 : else if ( nTopDiff > 0 )
107 : {
108 4 : return true;
109 : }
110 : }
111 101 : else if ( ( mbR2L &&
112 0 : ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
113 265 : (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
114 202 : ( !mbR2L &&
115 101 : ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
116 101 : (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
117 : {
118 63 : return true;
119 : }
120 :
121 66 : return false;
122 : }
123 : };
124 : }
125 :
126 1 : SwContourCache::SwContourCache() :
127 1 : nPntCnt( 0 ), nObjCnt( 0 )
128 : {
129 1 : memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) );
130 1 : memset( pTextRanger, 0, sizeof(pTextRanger) );
131 1 : }
132 :
133 1 : SwContourCache::~SwContourCache()
134 : {
135 1 : for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
136 : ;
137 1 : }
138 :
139 5 : void SwContourCache::ClrObject( MSHORT nPos )
140 : {
141 : OSL_ENSURE( pTextRanger[ nPos ], "ClrObject: Allready cleared. Good Bye!" );
142 5 : nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
143 5 : delete pTextRanger[ nPos ];
144 5 : --nObjCnt;
145 5 : memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1,
146 10 : ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
147 5 : memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
148 10 : ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
149 5 : }
150 :
151 674 : void ClrContourCache( const SdrObject *pObj )
152 : {
153 674 : if( pContourCache && pObj )
154 18 : for( MSHORT i = 0; i < pContourCache->GetCount(); ++i )
155 5 : if( pObj == pContourCache->GetObject( i ) )
156 : {
157 5 : pContourCache->ClrObject( i );
158 5 : break;
159 : }
160 674 : }
161 :
162 822 : void ClrContourCache()
163 : {
164 822 : if( pContourCache )
165 : {
166 80 : for( MSHORT i = 0; i < pContourCache->GetCount();
167 0 : delete pContourCache->pTextRanger[ i++ ] )
168 : ;
169 40 : pContourCache->nObjCnt = 0;
170 40 : pContourCache->nPntCnt = 0;
171 : }
172 822 : }
173 :
174 : // #i68520#
175 1048 : 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 1048 : SwRect aRet;
182 1048 : const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
183 1078 : if( pFmt->GetSurround().IsContour() &&
184 30 : ( !pAnchoredObj->ISA(SwFlyFrm) ||
185 30 : ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
186 15 : static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) )
187 : {
188 15 : aRet = pAnchoredObj->GetObjRectWithSpaces();
189 15 : if( aRet.IsOver( rLine ) )
190 : {
191 15 : if( !pContourCache )
192 1 : pContourCache = new SwContourCache;
193 :
194 30 : aRet = pContourCache->ContourRect(
195 15 : pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
196 : }
197 : else
198 0 : aRet.Width( 0 );
199 : }
200 : else
201 : {
202 1033 : aRet = pAnchoredObj->GetObjRectWithSpaces();
203 : }
204 :
205 1048 : return aRet;
206 : }
207 :
208 15 : 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 15 : SwRect aRet;
213 15 : MSHORT nPos = 0; // Suche im Cache ...
214 30 : while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
215 0 : ++nPos;
216 15 : if( GetCount() == nPos ) // nicht gefunden
217 : {
218 5 : if( nObjCnt == POLY_CNT )
219 : {
220 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
221 0 : delete pTextRanger[ nObjCnt ];
222 : }
223 5 : ::basegfx::B2DPolyPolygon aPolyPolygon;
224 5 : ::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;
225 :
226 5 : 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 5 : PolyPolygon aPoly;
231 5 : if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) )
232 10 : aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)->
233 10 : GetFlyFrm()->Frm().SVRect() );
234 5 : aPolyPolygon.clear();
235 5 : 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 5 : const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace();
248 5 : const SvxULSpaceItem &rULSpace = pFmt->GetULSpace();
249 5 : memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
250 5 : memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
251 5 : pSdrObj[ 0 ] = pObj; // due to #37347 the Object must be entered only
252 : // after GetContour()
253 : pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
254 10 : (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(),
255 10 : pFmt->GetSurround().IsOutside(), sal_False, pFrm->IsVertical() );
256 5 : pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
257 5 : pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );
258 :
259 5 : 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 5 : nPntCnt += pTextRanger[ 0 ]->GetPointCount();
277 10 : while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
278 : {
279 0 : nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
280 0 : delete pTextRanger[ nObjCnt ];
281 5 : }
282 : }
283 10 : 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 15 : SWRECTFN( pFrm )
293 15 : long nTmpTop = (rLine.*fnRect->fnGetTop)();
294 : // fnGetBottom is top + height
295 15 : long nTmpBottom = (rLine.*fnRect->fnGetBottom)();
296 :
297 15 : Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );
298 :
299 15 : LongDqPtr pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );
300 :
301 : MSHORT nCount;
302 15 : if( 0 != ( nCount = pTmp->size() ) )
303 : {
304 15 : MSHORT nIdx = 0;
305 30 : while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
306 0 : ++nIdx;
307 15 : bool bOdd = (nIdx % 2);
308 15 : bool bSet = true;
309 15 : if( bOdd )
310 0 : --nIdx; // within interval
311 15 : 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 15 : if( bSet && nIdx < nCount )
320 : {
321 30 : (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
322 45 : (rLine.*fnRect->fnGetHeight)() );
323 15 : (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
324 15 : (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
325 : }
326 : }
327 15 : return aRet;
328 : }
329 :
330 :
331 14294 : SwTxtFly::SwTxtFly() :
332 : pPage(0),
333 : mpCurrAnchoredObj(0),
334 : pCurrFrm(0),
335 : pMaster(0),
336 : mpAnchoredObjList(0),
337 : nMinBottom(0),
338 : nNextTop(0),
339 14294 : nIndex(0)
340 : {
341 14294 : }
342 :
343 7854 : SwTxtFly::SwTxtFly( const SwTxtFrm *pFrm )
344 : {
345 7854 : CtorInitTxtFly( pFrm );
346 7854 : }
347 :
348 10131 : SwTxtFly::SwTxtFly( const SwTxtFly& rTxtFly )
349 : {
350 10131 : pPage = rTxtFly.pPage;
351 10131 : mpCurrAnchoredObj = rTxtFly.mpCurrAnchoredObj;
352 10131 : pCurrFrm = rTxtFly.pCurrFrm;
353 10131 : pMaster = rTxtFly.pMaster;
354 10131 : if( rTxtFly.mpAnchoredObjList )
355 : {
356 2651 : mpAnchoredObjList = new SwAnchoredObjList( *(rTxtFly.mpAnchoredObjList) );
357 : }
358 : else
359 : {
360 7480 : mpAnchoredObjList = NULL;
361 : }
362 :
363 10131 : bOn = rTxtFly.bOn;
364 10131 : bLeftSide = rTxtFly.bLeftSide;
365 10131 : bTopRule = rTxtFly.bTopRule;
366 10131 : nMinBottom = rTxtFly.nMinBottom;
367 10131 : nNextTop = rTxtFly.nNextTop;
368 10131 : nIndex = rTxtFly.nIndex;
369 10131 : mbIgnoreCurrentFrame = rTxtFly.mbIgnoreCurrentFrame;
370 10131 : mbIgnoreContour = rTxtFly.mbIgnoreContour;
371 10131 : mbIgnoreObjsInHeaderFooter = rTxtFly.mbIgnoreObjsInHeaderFooter;
372 10131 : }
373 :
374 32279 : SwTxtFly::~SwTxtFly()
375 : {
376 32279 : delete mpAnchoredObjList;
377 32279 : }
378 :
379 22148 : void SwTxtFly::CtorInitTxtFly( const SwTxtFrm *pFrm )
380 : {
381 22148 : mbIgnoreCurrentFrame = sal_False;
382 22148 : mbIgnoreContour = sal_False;
383 : // #118809#
384 22148 : mbIgnoreObjsInHeaderFooter = sal_False;
385 22148 : pPage = pFrm->FindPageFrm();
386 22148 : const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
387 : // #i68520#
388 22148 : mpCurrAnchoredObj = pTmp;
389 22148 : pCurrFrm = pFrm;
390 22148 : pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
391 : // #i68520#
392 22148 : 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 22148 : bOn = pPage->GetSortedObjs() != 0;
399 22148 : bTopRule = sal_True;
400 22148 : bLeftSide = sal_False;
401 22148 : nMinBottom = 0;
402 22148 : nIndex = ULONG_MAX;
403 22148 : }
404 :
405 :
406 3956 : SwRect SwTxtFly::_GetFrm( const SwRect &rRect, sal_Bool bTop ) const
407 : {
408 3956 : SwRect aRet;
409 3956 : if( ForEach( rRect, &aRet, sal_True ) )
410 : {
411 1057 : SWRECTFN( pCurrFrm )
412 1057 : if( bTop )
413 1057 : (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );
414 :
415 : // 8110: Do not always adapt the bottom
416 1057 : const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
417 1057 : const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
418 1258 : if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
419 201 : (aRet.*fnRect->fnGetHeight)() < 0 )
420 856 : (aRet.*fnRect->fnSetBottom)( nRectBottom );
421 : }
422 3956 : return aRet;
423 : }
424 :
425 :
426 767 : sal_Bool SwTxtFly::IsAnyFrm() const
427 : {
428 767 : SWAP_IF_SWAPPED( pCurrFrm )
429 :
430 : OSL_ENSURE( bOn, "IsAnyFrm: Why?" );
431 1534 : SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
432 1534 : pCurrFrm->Prt().SSize() );
433 :
434 767 : const sal_Bool bRet = ForEach( aRect, NULL, sal_False );
435 767 : UNDO_SWAP( pCurrFrm )
436 767 : return bRet;
437 : }
438 :
439 917 : sal_Bool SwTxtFly::IsAnyObj( const SwRect &rRect ) const
440 : {
441 : OSL_ENSURE( bOn, "SwTxtFly::IsAnyObj: Who's knocking?" );
442 :
443 917 : SwRect aRect( rRect );
444 917 : if ( aRect.IsEmpty() )
445 1834 : aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
446 1834 : pCurrFrm->Prt().SSize() );
447 :
448 917 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
449 917 : 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 2178 : for ( MSHORT i = 0; i < pSorted->Count(); ++i )
453 : {
454 1534 : const SwAnchoredObject* pObj = (*pSorted)[i];
455 :
456 1534 : const SwRect aBound( pObj->GetObjRectWithSpaces() );
457 :
458 : // Optimization
459 1534 : if( pObj->GetObjRect().Left() > aRect.Right() )
460 546 : continue;
461 :
462 : // #i68520#
463 988 : if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
464 273 : return sal_True;
465 : }
466 : }
467 644 : return sal_False;
468 : }
469 :
470 793 : const SwCntntFrm* SwTxtFly::_GetMaster()
471 : {
472 793 : pMaster = pCurrFrm;
473 2773 : while( pMaster && pMaster->IsFollow() )
474 1187 : pMaster = (SwCntntFrm*)pMaster->FindMaster();
475 793 : return pMaster;
476 : }
477 :
478 :
479 138 : sal_Bool SwTxtFly::DrawTextOpaque( SwDrawTextInfo &rInf )
480 : {
481 138 : SwSaveClip aClipSave( rInf.GetpOut() );
482 138 : SwRect aRect( rInf.GetPos(), rInf.GetSize() );
483 138 : if( rInf.GetSpace() )
484 : {
485 0 : xub_StrLen nTmpLen = STRING_LEN == rInf.GetLen() ? rInf.GetText().getLength() :
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()[ 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 138 : if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
504 : {
505 78 : SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
506 78 : aRect.Intersection( aClipRect );
507 : }
508 :
509 276 : SwRegionRects aRegion( aRect );
510 :
511 138 : bool bOpaque = false;
512 : // #i68520#
513 : const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
514 0 : ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
515 138 : : SAL_MAX_UINT32;
516 : OSL_ENSURE( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
517 :
518 : // #i68520#
519 138 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
520 138 : if ( bOn && nCount > 0 )
521 : {
522 138 : MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
523 311 : for( MSHORT i = 0; i < nCount; ++i )
524 : {
525 : // #i68520#
526 173 : const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
527 332 : if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
528 346 : mpCurrAnchoredObj != pTmpAnchoredObj )
529 : {
530 : // #i68520#
531 159 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj);
532 159 : 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 0 : ) &&
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 138 : Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
571 138 : const Point &rOld = rInf.GetPos();
572 138 : rInf.SetPos( aPos );
573 :
574 138 : if( !bOpaque )
575 : {
576 138 : if( rInf.GetKern() )
577 0 : rInf.GetFont()->_DrawStretchText( rInf );
578 : else
579 138 : rInf.GetFont()->_DrawText( rInf );
580 138 : rInf.SetPos( rOld );
581 138 : 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 138 : return sal_True;
600 : }
601 :
602 :
603 55 : void SwTxtFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
604 : const SwTxtPaintInfo &rInf, sal_Bool bNoGraphic )
605 : {
606 55 : SwRegionRects aRegion( rRect );
607 : OSL_ENSURE( !bTopRule, "DrawFlyRect: Wrong TopRule" );
608 : // #i68520#
609 55 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
610 55 : if ( bOn && nCount > 0 )
611 : {
612 55 : MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
613 131 : for( MSHORT i = 0; i < nCount; ++i )
614 : {
615 : // #i68520#
616 76 : const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
617 228 : if( mpCurrAnchoredObj != pAnchoredObjTmp &&
618 152 : dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp) )
619 : {
620 : // #i68520#
621 76 : 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 76 : const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
628 : // #i47804# - consider transparent graphics
629 : // and OLE objects.
630 : bool bClipFlyArea =
631 76 : ( ( SURROUND_THROUGHT == rSur.GetSurround() )
632 : // #i68520#
633 0 : ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
634 152 : : !rSur.IsContour() ) &&
635 152 : !pFly->IsBackgroundTransparent() &&
636 359 : !pFly->IsShadowTransparent() &&
637 152 : ( !pFly->Lower() ||
638 97 : !pFly->Lower()->IsNoTxtFrm() ||
639 97 : !static_cast<const SwNoTxtFrm*>(pFly->Lower())->IsTransparent() );
640 76 : if ( bClipFlyArea )
641 : {
642 : // #i68520#
643 55 : SwRect aFly( pAnchoredObjTmp->GetObjRect() );
644 : // OD 24.01.2003 #106593#
645 55 : ::SwAlignRect( aFly, pPage->getRootFrm()->GetCurrShell() );
646 55 : if( aFly.Width() > 0 && aFly.Height() > 0 )
647 55 : aRegion -= aFly;
648 : }
649 : }
650 : }
651 : }
652 :
653 110 : for( MSHORT i = 0; i < aRegion.size(); ++i )
654 : {
655 55 : if ( bNoGraphic )
656 55 : pOut->DrawRect( aRegion[i].SVRect() );
657 : else
658 : {
659 : OSL_ENSURE( ((SvxBrushItem*)-1) != rInf.GetBrushItem(),
660 : "DrawRect: Uninitialized BrushItem!" );
661 0 : ::DrawGraphic( rInf.GetBrushItem(), 0, 0, pOut, rInf.GetBrushRect(),
662 0 : aRegion[i] );
663 : }
664 55 : }
665 55 : }
666 :
667 : // #i26945# - change first parameter
668 : // Now it's the <SwAnchoredObject> instance of the floating screen object
669 1526 : 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 1526 : if( _pAnchoredObj != mpCurrAnchoredObj )
676 : {
677 : // #i26945#
678 1105 : const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
679 : // #102344# Ignore connectors which have one or more connections
680 1105 : 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 1105 : 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 1272 : sal_Bool bEvade = !mpCurrAnchoredObj ||
714 1272 : Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);
715 :
716 1105 : 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 167 : if ( !bTopRule )
725 80 : bEvade = sal_True;
726 : else
727 : {
728 : // Within chained Flys we only avoid Lower
729 : // #i68520#
730 87 : const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain();
731 87 : if ( !rChain.GetPrev() && !rChain.GetNext() )
732 : {
733 : // #i26945#
734 87 : const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
735 : // #i68520#
736 87 : const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor();
737 :
738 : // If <mpCurrAnchoredObj> is anchored as character, its content
739 : // does not wrap around pNew
740 87 : 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 87 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
748 : {
749 2 : if (FLY_AT_PAGE == rCurrA.GetAnchorId())
750 : {
751 0 : bEvade = sal_True;
752 : }
753 : else
754 2 : return sal_False;
755 : }
756 85 : else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
757 11 : return sal_False; // Page anchored ones only avoid page anchored ones
758 74 : else if (FLY_AT_FLY == rNewA.GetAnchorId())
759 0 : bEvade = sal_True; // Non-page anchored ones avoid frame anchored ones
760 74 : 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 74 : return sal_False;
770 : }
771 : }
772 :
773 : // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
774 : // #i68520#
775 80 : bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
776 80 : if( bEvade )
777 : {
778 : // #i68520#
779 49 : SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
780 49 : if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
781 6 : bEvade = sal_False;
782 : }
783 : }
784 :
785 1018 : if ( bEvade )
786 : {
787 : // #i26945#
788 981 : const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
789 : OSL_ENSURE( FLY_AS_CHAR != rNewA.GetAnchorId(),
790 : "Don't call GetTop with a FlyInCntFrm" );
791 981 : if (FLY_AT_PAGE == rNewA.GetAnchorId())
792 130 : 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 851 : const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
801 851 : if( pTmp == pCurrFrm )
802 336 : return sal_True;
803 515 : 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 515 : else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() )
814 : {
815 : pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
816 27 : ->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 515 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
830 1280 : if ( ( pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
831 1030 : !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) &&
832 515 : ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
833 : {
834 314 : return sal_True;
835 : }
836 :
837 201 : const SwFrm* pHeader = 0;
838 453 : if ( pCurrFrm->GetNext() != pTmp &&
839 359 : ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
840 : // #i13832#, #i24135# wrap around objects in page header
841 316 : ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
842 8 : 0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
843 16 : !pHeader->IsFooterFrm() &&
844 8 : pCurrFrm->IsInDocBody() ) ) )
845 : {
846 51 : if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
847 8 : return sal_True;
848 :
849 : // Compare indices:
850 : // The Index of the other is retrieved from the anchor attr.
851 43 : 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 43 : if( ULONG_MAX == nIndex )
858 38 : nIndex = pCurrFrm->GetNode()->GetIndex();
859 :
860 43 : if( nIndex >= nTmpIndex )
861 0 : return sal_True;
862 : }
863 : }
864 : }
865 651 : return sal_False;
866 : }
867 :
868 : // #i68520#
869 2827 : 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 2827 : SWAP_IF_SWAPPED( pCurrFrm )
876 :
877 2827 : const SwSortedObjs *pSorted = pPage->GetSortedObjs();
878 2827 : 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 2827 : const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
882 2827 : const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
883 : // #i40155# - check, if frame is marked not to wrap
884 8349 : const bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
885 8471 : ( !pCurrFrm->IsInFtn() && !bFooterHeader ) );
886 :
887 2827 : bOn = sal_False;
888 :
889 2827 : if( nCount && bWrapAllowed )
890 : {
891 : // #i68520#
892 2700 : mpAnchoredObjList = new SwAnchoredObjList();
893 :
894 : // #i28701# - consider complete frame area for new
895 : // text wrapping
896 2700 : SwRect aRect;
897 2700 : if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) )
898 : {
899 5 : aRect = pCurrFrm->Prt();
900 5 : aRect += pCurrFrm->Frm().Pos();
901 : }
902 : else
903 : {
904 2695 : aRect = pCurrFrm->Frm();
905 : }
906 : // Make ourselves a little smaller than we are,
907 : // so that 1-Twip-overlappings are ignored (#49532)
908 2700 : SWRECTFN( pCurrFrm )
909 2700 : const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
910 2700 : const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
911 2700 : const sal_Bool bR2L = pCurrFrm->IsRightToLeft();
912 :
913 2700 : const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess();
914 :
915 7476 : 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 4776 : SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
926 18924 : if ( !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
927 19111 : !pAnchoredObj->ConsiderForTextWrap() ||
928 2214 : ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
929 1107 : pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
930 : {
931 4148 : continue;
932 : }
933 :
934 3878 : const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
935 11055 : if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
936 3299 : (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
937 8196 : (aBound.*fnRect->fnGetBottom)() ) > 0 ||
938 7002 : nLeft > (aBound.*fnRect->fnGetRight)() ||
939 1526 : (aBound.*fnRect->fnGetHeight)() >
940 1526 : 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
941 : {
942 2352 : continue;
943 : }
944 :
945 : // #i26945# - pass <pAnchoredObj> to method
946 : // <GetTop(..)> instead of only the <SdrObject> instance of the
947 : // anchored object
948 1526 : 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 788 : AnchoredObjOrder( bR2L, fnRect ) );
962 :
963 788 : mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
964 : }
965 :
966 788 : const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
967 : // #i68520#
968 788 : 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 0 : nMinBottom = ( bVert && nMinBottom ) ?
975 0 : std::min( nMinBottom, aBound.Left() ) :
976 0 : std::max( nMinBottom, (aBound.*fnRect->fnGetBottom)() );
977 : }
978 :
979 788 : bOn = sal_True;
980 : }
981 : }
982 2700 : if( nMinBottom )
983 : {
984 0 : SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
985 0 : if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
986 0 : nMinBottom = nMax;
987 2700 : }
988 : }
989 : else
990 : {
991 : // #i68520#
992 127 : mpAnchoredObjList = new SwAnchoredObjList();
993 : }
994 :
995 2827 : UNDO_SWAP( pCurrFrm )
996 :
997 : // #i68520#
998 2827 : return mpAnchoredObjList;
999 : }
1000 :
1001 6600 : SwTwips SwTxtFly::CalcMinBottom() const
1002 : {
1003 6600 : SwTwips nRet = 0;
1004 6600 : const SwCntntFrm *pLclMaster = GetMaster();
1005 : OSL_ENSURE(pLclMaster, "SwTxtFly without master");
1006 6600 : const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : NULL;
1007 6600 : const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0;
1008 6600 : if( nCount )
1009 : {
1010 406 : SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
1011 963 : for( sal_uInt32 i = 0; i < nCount; i++ )
1012 : {
1013 557 : SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
1014 557 : const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
1015 557 : 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 = std::max( nRet, aBound.Bottom() );
1024 : }
1025 : }
1026 : }
1027 406 : SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
1028 406 : pCurrFrm->GetUpper()->Prt().Bottom();
1029 406 : if( nRet > nMax )
1030 0 : nRet = nMax;
1031 : }
1032 6600 : return nRet;
1033 : }
1034 :
1035 :
1036 4723 : sal_Bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, sal_Bool bAvoid ) const
1037 : {
1038 4723 : SWAP_IF_SWAPPED( pCurrFrm )
1039 :
1040 4723 : sal_Bool bRet = sal_False;
1041 : // #i68520#
1042 4723 : SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1043 4723 : if ( bOn && nCount > 0 )
1044 : {
1045 3813 : for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1046 : {
1047 : // #i68520#
1048 2854 : const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1049 :
1050 2854 : SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1051 :
1052 : // Optimierung
1053 2854 : SWRECTFN( pCurrFrm )
1054 2854 : if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
1055 1990 : break;
1056 : // #i68520#
1057 2465 : if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
1058 : {
1059 : // #i68520#
1060 1749 : const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) );
1061 1749 : const SwFmtSurround &rSur = pFmt->GetSurround();
1062 1749 : 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 1594 : const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
1068 3699 : if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
1069 511 : ( !rSur.IsAnchorOnly() ||
1070 : // #i68520#
1071 0 : GetMaster() == pAnchoredObj->GetAnchorFrm() ||
1072 0 : ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
1073 0 : (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
1074 2677 : || aRect.Top() == FAR_AWAY )
1075 1048 : 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 1273 : if ( mbIgnoreCurrentFrame &&
1087 35 : GetMaster() == pAnchoredObj->GetAnchorFrm() )
1088 11 : continue;
1089 :
1090 1227 : if( pRect )
1091 : {
1092 : // #i68520#
1093 1072 : SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
1094 1072 : if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
1095 15 : continue;
1096 2144 : if( !bRet || (
1097 30 : ( !pCurrFrm->IsRightToLeft() &&
1098 15 : ( (aFly.*fnRect->fnGetLeft)() <
1099 30 : (pRect->*fnRect->fnGetLeft)() ) ) ||
1100 15 : ( pCurrFrm->IsRightToLeft() &&
1101 0 : ( (aFly.*fnRect->fnGetRight)() >
1102 0 : (pRect->*fnRect->fnGetRight)() ) ) ) )
1103 1057 : *pRect = aFly;
1104 1072 : if( rSur.IsContour() )
1105 : {
1106 15 : bRet = sal_True;
1107 15 : continue;
1108 : }
1109 : }
1110 1212 : bRet = sal_True;
1111 1212 : break;
1112 : }
1113 : }
1114 : }
1115 :
1116 4723 : UNDO_SWAP( pCurrFrm )
1117 :
1118 4723 : return bRet;
1119 : }
1120 :
1121 :
1122 : // #i68520#
1123 1072 : SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
1124 : {
1125 1072 : SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
1126 1072 : SwAnchoredObjList::size_type nRet = 0;
1127 2218 : while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
1128 74 : ++nRet;
1129 1072 : return nRet;
1130 : }
1131 :
1132 : // #i68520#
1133 378 : 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 378 : SWRECTFN( pCurrFrm )
1141 : // #118796# - correct determination of right of printing area
1142 378 : SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1143 378 : SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
1144 378 : SwRect aLine( rLine );
1145 378 : (aLine.*fnRect->fnSetRight)( nRight );
1146 378 : (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 378 : bool bStop = false;
1157 : // #i68520#
1158 378 : SwAnchoredObjList::size_type nPos = 0;
1159 :
1160 : // #i68520#
1161 1167 : while( nPos < mpAnchoredObjList->size() && !bStop )
1162 : {
1163 411 : if( nPos == nFlyPos )
1164 : {
1165 378 : ++nPos;
1166 756 : continue;
1167 : }
1168 : // #i68520#
1169 33 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
1170 33 : if ( pNext == mpCurrAnchoredObj )
1171 0 : continue;
1172 33 : eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1173 33 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1174 0 : continue;
1175 :
1176 : const SwRect aTmp( SwContourCache::CalcBoundRect
1177 33 : ( pNext, aLine, pCurrFrm, nFlyRight, sal_True ) );
1178 33 : 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 33 : const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
1190 33 : 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 33 : 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 33 : 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 378 : (rFly.*fnRect->fnSetRight)( nRight );
1219 378 : }
1220 :
1221 : // #i68520#
1222 39 : 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 39 : SWRECTFN( pCurrFrm )
1229 : // #118796# - correct determination of left of printing area
1230 39 : SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1231 39 : const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();
1232 :
1233 39 : if( nLeft > nFlyLeft )
1234 0 : nLeft = rFly.Left();
1235 :
1236 39 : SwRect aLine( rLine );
1237 39 : (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 39 : SwAnchoredObjList::size_type nMyPos = nFlyPos;
1247 78 : while( ++nFlyPos < mpAnchoredObjList->size() )
1248 : {
1249 : // #i68520#
1250 10 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1251 10 : const SwRect aTmp( pNext->GetObjRectWithSpaces() );
1252 10 : if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
1253 10 : break;
1254 : }
1255 :
1256 117 : while( nFlyPos )
1257 : {
1258 41 : if( --nFlyPos == nMyPos )
1259 78 : continue;
1260 : // #i68520#
1261 2 : const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
1262 2 : if( pNext == mpCurrAnchoredObj )
1263 0 : continue;
1264 2 : SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
1265 2 : if( SURROUND_THROUGHT == eSurroundForTextWrap )
1266 0 : continue;
1267 :
1268 : const SwRect aTmp( SwContourCache::CalcBoundRect
1269 2 : ( pNext, aLine, pCurrFrm, nFlyLeft, sal_False ) );
1270 :
1271 2 : if( (aTmp.*fnRect->fnGetLeft)() < nFlyLeft && aTmp.IsOver( aLine ) )
1272 : {
1273 : // #118796# - no '+1', because <..fnGetRight>
1274 : // returns the correct value.
1275 2 : SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
1276 2 : if ( nLeft <= nTmpRight )
1277 2 : nLeft = nTmpRight;
1278 :
1279 4 : break;
1280 : }
1281 : }
1282 39 : (rFly.*fnRect->fnSetLeft)( nLeft );
1283 39 : }
1284 :
1285 : // #i68520#
1286 1072 : SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
1287 : const SwRect &rLine ) const
1288 : {
1289 1072 : SWRECTFN( pCurrFrm )
1290 :
1291 1072 : const long nXPos = pCurrFrm->IsRightToLeft() ?
1292 : rLine.Right() :
1293 1072 : (rLine.*fnRect->fnGetLeft)();
1294 :
1295 : SwRect aFly = mbIgnoreContour ?
1296 59 : pAnchoredObj->GetObjRectWithSpaces() :
1297 : SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
1298 1131 : nXPos, ! pCurrFrm->IsRightToLeft() );
1299 :
1300 1072 : if( !aFly.Width() )
1301 0 : return aFly;
1302 :
1303 : // so the line may grow up to the lower edge of the frame
1304 1072 : SetNextTop( (aFly.*fnRect->fnGetBottom)() );
1305 1072 : 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 1072 : switch( _GetSurroundForTextWrap( pAnchoredObj ) )
1317 : {
1318 : case SURROUND_LEFT :
1319 : {
1320 345 : CalcRightMargin( aFly, nFlyPos, rLine );
1321 345 : break;
1322 : }
1323 : case SURROUND_RIGHT :
1324 : {
1325 6 : CalcLeftMargin( aFly, nFlyPos, rLine );
1326 6 : break;
1327 : }
1328 : case SURROUND_NONE :
1329 : {
1330 33 : CalcRightMargin( aFly, nFlyPos, rLine );
1331 33 : CalcLeftMargin( aFly, nFlyPos, rLine );
1332 33 : break;
1333 : }
1334 : default:
1335 688 : break;
1336 : }
1337 1072 : 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 1107 : SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
1349 : {
1350 1107 : const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
1351 1107 : const SwFmtSurround &rFlyFmt = pFmt->GetSurround();
1352 1107 : SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround();
1353 :
1354 1107 : 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 1107 : if( SURROUND_THROUGHT == eSurroundForTextWrap ||
1366 : SURROUND_NONE == eSurroundForTextWrap )
1367 9 : return eSurroundForTextWrap;
1368 :
1369 : // left is left and right is right
1370 1098 : 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 1098 : if ( SURROUND_IDEAL == eSurroundForTextWrap )
1380 : {
1381 404 : SWRECTFN( pCurrFrm )
1382 404 : const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
1383 404 : const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
1384 404 : const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1385 404 : long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
1386 404 : long nFlyRight = (aRect.*fnRect->fnGetRight)();
1387 :
1388 404 : if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
1389 0 : eSurroundForTextWrap = SURROUND_PARALLEL;
1390 : else
1391 : {
1392 404 : long nLeft = nFlyLeft - nCurrLeft;
1393 404 : long nRight = nCurrRight - nFlyRight;
1394 404 : if( nFlyRight - nFlyLeft > FRAME_MAX )
1395 : {
1396 369 : if( nLeft < nRight )
1397 0 : nLeft = 0;
1398 : else
1399 369 : nRight = 0;
1400 : }
1401 404 : if( nLeft < TEXT_MIN )
1402 32 : nLeft = 0;
1403 404 : if( nRight < TEXT_MIN )
1404 369 : nRight = 0;
1405 404 : if( nLeft )
1406 372 : eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
1407 : else
1408 32 : eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
1409 : }
1410 : }
1411 :
1412 1098 : 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 99 : }
1426 :
1427 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|