xref: /aoo41x/main/sw/source/core/text/txtfly.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <vcl/outdev.hxx>
32 #include <vcl/virdev.hxx>
33 
34 #include "viewsh.hxx"
35 #include "pagefrm.hxx"
36 #include "rootfrm.hxx"
37 #include "viewimp.hxx"		// SwViewImp
38 #include "pam.hxx"			// SwPosition
39 #include "swregion.hxx"		// SwRegionRects
40 #include "dcontact.hxx"		// SwContact
41 #include "dflyobj.hxx"		// SdrObject
42 #include "flyfrm.hxx"	  // SwFlyFrm
43 #include "frmtool.hxx"	  // ::DrawGraphic
44 #include "porfld.hxx"		// SwGrfNumPortion
45 #include "txtfrm.hxx"     // SwTxtFrm
46 #include "itrform2.hxx"   // SwTxtFormatter
47 #include "porfly.hxx"     // NewFlyCntPortion
48 #include "porfld.hxx"     // SwGrfNumPortion
49 #include "txtfly.hxx"     // SwTxtFly
50 #include "txtpaint.hxx"   // SwSaveClip
51 #include "txtatr.hxx"     // SwTxtFlyCnt
52 #include "txtcfg.hxx"
53 #include "notxtfrm.hxx"
54 #include "flyfrms.hxx"
55 #include "fmtcnct.hxx"  // SwFmtChain
56 #include <pormulti.hxx> 	// SwMultiPortion
57 #include <svx/obj3d.hxx>
58 #include <editeng/txtrange.hxx>
59 #include <editeng/lrspitem.hxx>
60 #include <editeng/ulspitem.hxx>
61 // --> OD 2004-06-16 #i28701#
62 #include <editeng/lspcitem.hxx>
63 // <--
64 #include <txtflcnt.hxx>
65 #include <fmtsrnd.hxx>
66 #include <fmtanchr.hxx>
67 #include <fmtflcnt.hxx>
68 #include <frmfmt.hxx>
69 #include <pagedesc.hxx> // SwPageDesc
70 #include <tgrditem.hxx>
71 #include <sortedobjs.hxx>
72 #include <layouter.hxx>
73 #include <IDocumentDrawModelAccess.hxx>
74 #include <IDocumentLayoutAccess.hxx>
75 #include <IDocumentSettingAccess.hxx>
76 #include <svx/obj3d.hxx>
77 #include <editeng/txtrange.hxx>
78 #include <editeng/lrspitem.hxx>
79 #include <editeng/ulspitem.hxx>
80 #include <editeng/lspcitem.hxx>
81 #include <svx/svdoedge.hxx>
82 #include "doc.hxx"
83 
84 #ifdef DBG_UTIL
85 #include "viewopt.hxx"	// SwViewOptions, nur zum Testen (Test2)
86 #include "doc.hxx"
87 #endif
88 
89 #ifdef VERT_DISTANCE
90 #include <math.h>
91 #endif
92 
93 
94 using namespace ::com::sun::star;
95 
96 /*****************************************************************************
97  * Beschreibung:
98  * Die Klasse SwTxtFly soll die Universalschnittstelle zwischen der
99  * Formatierung/Textausgabe und den u.U. ueberlappenden freifliegenden
100  * Frames sein.
101  * Waehrend der Formatierung erkundigt sich der Formatierer beim SwTxtFly,
102  * ob ein bestimmter Bereich durch die Attribute eines ueberlappenden
103  * Frames vorliegt. Solche Bereiche werden in Form von Dummy-Portions
104  * abgebildet.
105  * Die gesamte Textausgabe und Retusche wird ebenfalls an ein SwTxtFly
106  * weitergeleitet. Dieser entscheidet, ob Textteile geclippt werden muessen
107  * und zerteilt z.B. die Bereiche bei einem DrawRect.
108  * Zu beachten ist, dass alle freifliegenden Frames in einem nach TopLeft
109  * sortiertem PtrArray an der Seite zu finden sind. Intern wird immer nur
110  * in dokumentglobalen Werten gerechnet. Die IN- und OUT-Parameter sind
111  * jedoch in den meisten Faellen an die Beduerfnisse des LineIters
112  * zugeschnitten, d.h. sie werden in frame- oder windowlokalen Koordinaten
113  * konvertiert.
114  * Wenn mehrere Frames mit Umlaufattributen in einer Zeile liegen,
115  * ergeben sich unterschiedliche Auswirkungen fuer den Textfluss:
116  *
117  *		L/R    P	 L	   R	 K
118  *		 P	 -P-P- -P-L  -P R- -P K
119  *		 L	 -L P- -L L  -L R- -L K
120  *		 R	  R-P-	R-L   R R-	R K
121  *		 K	  K P-	K L   K R-	K K
122  *
123  * (P=parallel, L=links, R=rechts, K=kein Umlauf)
124  *
125  * Das Verhalten so beschreiben:
126  * Jeder Rahmen kann Text verdraengen, wobei der Einfluss allerdings nur
127  * bis zum naechsten Rahmen reicht.
128  *****************************************************************************/
129 
130 void SwTxtFormatter::CalcUnclipped( SwTwips& rTop, SwTwips& rBottom )
131 {
132     ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
133             "SwTxtFormatter::CalcUnclipped with unswapped frame" )
134 
135 	long nFlyAsc, nFlyDesc;
136     // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
137     //lcl_MaxAscDescent( pCurr, rTop, rBottom, nFlyAsc, nFlyDesc );
138     pCurr->MaxAscentDescent( rTop, rBottom, nFlyAsc, nFlyDesc );
139 	rTop = Y() + GetCurr()->GetAscent();
140 	rBottom = rTop + nFlyDesc;
141 	rTop -= nFlyAsc;
142 }
143 
144 /*************************************************************************
145  * SwTxtFormatter::UpdatePos() aktualisiert die Referenzpunkte der zeichengeb.
146  * Objekte, z. B. nach Adjustierung ( rechtsbuendig, Blocksatz etc. )
147  * ( hauptsaechlich Korrrektur der X-Position )
148  *************************************************************************/
149 
150 void SwTxtFormatter::UpdatePos( SwLineLayout *pCurrent, Point aStart,
151 	xub_StrLen nStartIdx, sal_Bool bAllWays ) const
152 {
153     ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
154             "SwTxtFormatter::UpdatePos with unswapped frame" )
155 
156     if( GetInfo().IsTest() )
157 		return;
158     SwLinePortion *pFirst = pCurrent->GetFirstPortion();
159     SwLinePortion *pPos = pFirst;
160 	SwTxtPaintInfo aTmpInf( GetInfo() );
161     aTmpInf.SetpSpaceAdd( pCurrent->GetpLLSpaceAdd() );
162 	aTmpInf.ResetSpaceIdx();
163     aTmpInf.SetKanaComp( pCurrent->GetpKanaComp() );
164     aTmpInf.ResetKanaIdx();
165 
166 	// Die Groesse des Frames
167 	aTmpInf.SetIdx( nStartIdx );
168 	aTmpInf.SetPos( aStart );
169 
170 	long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
171     // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
172     //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
173     pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
174 
175     KSHORT nTmpHeight = pCurrent->GetRealHeight();
176     KSHORT nAscent = pCurrent->GetAscent() + nTmpHeight - pCurrent->Height();
177     objectpositioning::AsCharFlags nFlags = AS_CHAR_ULSPACE;
178 	if( GetMulti() )
179 	{
180 		aTmpInf.SetDirection( GetMulti()->GetDirection() );
181 		if( GetMulti()->HasRotation() )
182 		{
183             nFlags |= AS_CHAR_ROTATE;
184 			if( GetMulti()->IsRevers() )
185 			{
186                 nFlags |= AS_CHAR_REVERSE;
187 				aTmpInf.X( aTmpInf.X() - nAscent );
188 			}
189 			else
190 				aTmpInf.X( aTmpInf.X() + nAscent );
191 		}
192         else
193         {
194             if ( GetMulti()->IsBidi() )
195                 nFlags |= AS_CHAR_BIDI;
196 			aTmpInf.Y( aTmpInf.Y() + nAscent );
197         }
198 	}
199 	else
200 		aTmpInf.Y( aTmpInf.Y() + nAscent );
201 
202 	while( pPos )
203 	{
204 		// bislang ist mir nur ein Fall bekannt, wo die Positionsaenderung
205 		// (verursacht durch das Adjustment) fuer eine Portion wichtig
206 		// sein koennte: Bei FlyCntPortions muss ein SetRefPoint erfolgen.
207 		if( ( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
208 			&& ( bAllWays || !IsQuick() ) )
209 		{
210             // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
211             //lcl_MaxAscDescent( pFirst, nTmpAscent, nTmpDescent,
212             //                  nFlyAsc, nFlyDesc, pPos );
213             pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
214 
215 			if( pPos->IsGrfNumPortion() )
216 			{
217 				if( !nFlyAsc && !nFlyDesc )
218 				{
219 					nTmpAscent = nAscent;
220 					nFlyAsc = nAscent;
221 					nTmpDescent = nTmpHeight - nAscent;
222 					nFlyDesc = nTmpDescent;
223 				}
224 				((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
225 												   nFlyAsc, nFlyDesc );
226 			}
227 			else
228 			{
229                 Point aBase( aTmpInf.GetPos() );
230                 if ( GetInfo().GetTxtFrm()->IsVertical() )
231                     GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aBase );
232 
233                 ((SwFlyCntPortion*)pPos)->SetBase( *aTmpInf.GetTxtFrm(),
234                     aBase, nTmpAscent, nTmpDescent, nFlyAsc,
235                     nFlyDesc, nFlags );
236 			}
237 		}
238 		if( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasFlyInCntnt() )
239 		{
240 			ASSERT( !GetMulti(), "Too much multi" );
241 			((SwTxtFormatter*)this)->pMulti = (SwMultiPortion*)pPos;
242 			SwLineLayout *pLay = &GetMulti()->GetRoot();
243             Point aSt( aTmpInf.X(), aStart.Y() );
244 
245             if ( GetMulti()->HasBrackets() )
246             {
247                 ASSERT( GetMulti()->IsDouble(), "Brackets only for doubles");
248                 aSt.X() += ((SwDoubleLinePortion*)GetMulti())->PreWidth();
249             }
250             else if( GetMulti()->HasRotation() )
251 			{
252                 aSt.Y() += pCurrent->GetAscent() - GetMulti()->GetAscent();
253                 if( GetMulti()->IsRevers() )
254                     aSt.X() += GetMulti()->Width();
255                 else
256 					aSt.Y() += GetMulti()->Height();
257 	   		}
258             else if ( GetMulti()->IsBidi() )
259                 // jump to end of the bidi portion
260                 aSt.X() += pLay->Width();
261 
262             xub_StrLen nStIdx = aTmpInf.GetIdx();
263 			do
264 			{
265 				UpdatePos( pLay, aSt, nStIdx, bAllWays );
266 				nStIdx = nStIdx + pLay->GetLen();
267 				aSt.Y() += pLay->Height();
268 				pLay = pLay->GetNext();
269 			} while ( pLay );
270 			((SwTxtFormatter*)this)->pMulti = NULL;
271 		}
272 		pPos->Move( aTmpInf );
273 		pPos = pPos->GetPortion();
274 	}
275 }
276 
277 /*************************************************************************
278  * SwTxtFormatter::AlignFlyInCntBase()
279  * richtet die zeichengeb. Objekte in Y-Richtung ggf. neu aus.
280  *************************************************************************/
281 
282 void SwTxtFormatter::AlignFlyInCntBase( long nBaseLine ) const
283 {
284     ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
285             "SwTxtFormatter::AlignFlyInCntBase with unswapped frame" )
286 
287 	if( GetInfo().IsTest() )
288 		return;
289 	SwLinePortion *pFirst = pCurr->GetFirstPortion();
290 	SwLinePortion *pPos = pFirst;
291     objectpositioning::AsCharFlags nFlags = AS_CHAR_NOFLAG;
292 	if( GetMulti() && GetMulti()->HasRotation() )
293 	{
294         nFlags |= AS_CHAR_ROTATE;
295 		if( GetMulti()->IsRevers() )
296             nFlags |= AS_CHAR_REVERSE;
297 	}
298 
299 	long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
300 
301 	while( pPos )
302 	{
303 		if( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
304 		{
305             // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
306             //lcl_MaxAscDescent( pFirst, nTmpAscent, nTmpDescent,
307             //                  nFlyAsc, nFlyDesc, pPos );
308             pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
309 
310 			if( pPos->IsGrfNumPortion() )
311 				((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
312 												   nFlyAsc, nFlyDesc );
313 			else
314 			{
315                 Point aBase;
316                 if ( GetInfo().GetTxtFrm()->IsVertical() )
317                 {
318                     nBaseLine = GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( nBaseLine );
319                     aBase = Point( nBaseLine, ((SwFlyCntPortion*)pPos)->GetRefPoint().Y() );
320                 }
321                 else
322                     aBase = Point( ((SwFlyCntPortion*)pPos)->GetRefPoint().X(), nBaseLine );
323 
324                 ((SwFlyCntPortion*)pPos)->SetBase( *GetInfo().GetTxtFrm(), aBase, nTmpAscent, nTmpDescent,
325 					nFlyAsc, nFlyDesc, nFlags );
326 			}
327 		}
328 		pPos = pPos->GetPortion();
329 	}
330 }
331 
332 /*************************************************************************
333  *                      SwTxtFly::ChkFlyUnderflow()
334  * This is called after the real height of the line has been calculated
335  * Therefore it is possible, that more flys from below intersect with the
336  * line, or that flys from above do not intersect with the line anymore
337  * We check this and return true if so, meaning that the line has to be
338  * formatted again
339  *************************************************************************/
340 
341 sal_Bool SwTxtFormatter::ChkFlyUnderflow( SwTxtFormatInfo &rInf ) const
342 {
343     ASSERT( rInf.GetTxtFly()->IsOn(), "SwTxtFormatter::ChkFlyUnderflow: why?" );
344 	if( GetCurr() )
345 	{
346 		// Erst pruefen wir, ob ueberhaupt ein Fly mit der Zeile ueberlappt.
347         // = GetLineHeight()
348         const long nHeight = GetCurr()->GetRealHeight();
349 		SwRect aLine( GetLeftMargin(), Y(), rInf.RealWidth(), nHeight );
350 
351         SwRect aLineVert( aLine );
352         if ( pFrm->IsVertical() )
353             pFrm->SwitchHorizontalToVertical( aLineVert );
354         SwRect aInter( rInf.GetTxtFly()->GetFrm( aLineVert ) );
355         if ( pFrm->IsVertical() )
356             pFrm->SwitchVerticalToHorizontal( aInter );
357 
358 		if( !aInter.HasArea() )
359 			return sal_False;
360 
361 		// Nun ueberpruefen wir jede Portion, die sich haette senken koennen,
362 		// ob sie mit dem Fly ueberlappt.
363 		const SwLinePortion *pPos = GetCurr()->GetFirstPortion();
364         aLine.Pos().Y() = Y() + GetCurr()->GetRealHeight() - GetCurr()->Height();
365         aLine.Height( GetCurr()->Height() );
366 
367 		while( pPos )
368 		{
369             aLine.Width( pPos->Width() );
370 
371             aLineVert = aLine;
372             if ( pFrm->IsVertical() )
373                 pFrm->SwitchHorizontalToVertical( aLineVert );
374             aInter = rInf.GetTxtFly()->GetFrm( aLineVert );
375             if ( pFrm->IsVertical() )
376                 pFrm->SwitchVerticalToHorizontal( aInter );
377 
378             // new flys from below?
379 			if( !pPos->IsFlyPortion() )
380 			{
381 				if( aInter.IsOver( aLine ) )
382 				{
383 					aInter._Intersection( aLine );
384 					if( aInter.HasArea() )
385 					{
386                         // to be evaluated during reformat of this line:
387                         // RealHeight including spacing
388 						rInf.SetLineHeight( KSHORT(nHeight) );
389                         // Height without extra spacing
390                         rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
391 						return sal_True;
392 					}
393 				}
394 			}
395             else
396             {
397                 // the fly portion is not anylonger intersected by a fly
398                 if ( ! aInter.IsOver( aLine ) )
399                 {
400                     rInf.SetLineHeight( KSHORT(nHeight) );
401                     rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
402                     return sal_True;
403                 }
404                 else
405                 {
406 					aInter._Intersection( aLine );
407 
408                     // no area means a fly has become invalid because of
409                     // lowering the line => reformat the line
410                     // we also have to reformat the line, if the fly size
411                     // differs from the intersection intervals size
412                     if( ! aInter.HasArea() ||
413                         ((SwFlyPortion*)pPos)->GetFixWidth() != aInter.Width() )
414 					{
415 						rInf.SetLineHeight( KSHORT(nHeight) );
416                         rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
417 						return sal_True;
418 					}
419 				}
420             }
421 
422 			aLine.Left( aLine.Left() + pPos->Width() );
423 			pPos = pPos->GetPortion();
424 		}
425 	}
426 	return sal_False;
427 }
428 
429 /*************************************************************************
430  * SwTxtFormatter::CalcFlyWidth()
431  * ermittelt das naechste Objekt, das in die restliche Zeile ragt und
432  * konstruiert die zugehoerige FlyPortion.
433  * Dazu wird SwTxtFly.GetFrm(..) benutzt.
434  *************************************************************************/
435 
436 // Durch Flys kann sich der rechte Rand verkuerzen.
437 
438 void SwTxtFormatter::CalcFlyWidth( SwTxtFormatInfo &rInf )
439 {
440     if( GetMulti() || rInf.GetFly() )
441 		return;
442 
443 	SwTxtFly *pTxtFly = rInf.GetTxtFly();
444 	if( !pTxtFly->IsOn() || rInf.IsIgnoreFly() )
445 		return;
446 
447 	const SwLinePortion *pLast = rInf.GetLast();
448 
449 	long nAscent;
450     long nTop = Y();
451     long nHeight;
452 
453     if( rInf.GetLineHeight() )
454     {
455         // real line height has already been calculated, we only have to
456         // search for intersections in the lower part of the strip
457         nAscent = pCurr->GetAscent();
458         nHeight = rInf.GetLineNettoHeight();
459         nTop += rInf.GetLineHeight() - nHeight;
460 	}
461 	else
462 	{
463         nAscent = pLast->GetAscent();
464         nHeight = pLast->Height();
465 
466         // we make a first guess for the lines real height
467         if ( ! pCurr->GetRealHeight() )
468             CalcRealHeight();
469 
470         if ( pCurr->GetRealHeight() > nHeight )
471             nTop += pCurr->GetRealHeight() - nHeight;
472         else
473             // important for fixed space between lines
474             nHeight = pCurr->GetRealHeight();
475 	}
476 
477     const long nLeftMar = GetLeftMargin();
478     const long nLeftMin = (rInf.X() || GetDropLeft()) ? nLeftMar : GetLeftMin();
479 
480     SwRect aLine( rInf.X() + nLeftMin, nTop, rInf.RealWidth() - rInf.X()
481 				  + nLeftMar - nLeftMin	, nHeight );
482 
483     SwRect aLineVert( aLine );
484     if ( pFrm->IsRightToLeft() )
485         pFrm->SwitchLTRtoRTL( aLineVert );
486 
487     if ( pFrm->IsVertical() )
488         pFrm->SwitchHorizontalToVertical( aLineVert );
489     SwRect aInter( pTxtFly->GetFrm( aLineVert ) );
490 
491     if ( pFrm->IsRightToLeft() )
492         pFrm->SwitchRTLtoLTR( aInter );
493 
494     if ( pFrm->IsVertical() )
495         pFrm->SwitchVerticalToHorizontal( aInter );
496 
497     if( aInter.IsOver( aLine ) )
498 	{
499         aLine.Left( rInf.X() + nLeftMar );
500 		sal_Bool bForced = sal_False;
501 		if( aInter.Left() <= nLeftMin )
502 		{
503 			SwTwips nFrmLeft = GetTxtFrm()->Frm().Left();
504 			if( GetTxtFrm()->Prt().Left() < 0 )
505 				nFrmLeft += GetTxtFrm()->Prt().Left();
506 			if( aInter.Left() < nFrmLeft )
507 				aInter.Left( nFrmLeft );
508 
509             long nAddMar = 0;
510             if ( pFrm->IsRightToLeft() )
511             {
512                 nAddMar = pFrm->Frm().Right() - Right();
513                 if ( nAddMar < 0 )
514                     nAddMar = 0;
515             }
516             else
517                 nAddMar = nLeftMar - nFrmLeft;
518 
519             aInter.Width( aInter.Width() + nAddMar );
520 			// Bei negativem Erstzeileneinzug setzen wir das Flag,
521 			// um anzuzeigen, dass der Einzug/Rand verschoben wurde
522 			// Dies muss beim DefaultTab an der Nullposition beruecksichtigt
523 			// werden.
524 			if( IsFirstTxtLine() && HasNegFirst() )
525 				bForced = sal_True;
526 		}
527 		aInter.Intersection( aLine );
528 		if( !aInter.HasArea() )
529 			return;
530 
531 		const sal_Bool bFullLine =	aLine.Left()  == aInter.Left() &&
532 								aLine.Right() == aInter.Right();
533 
534 		// Obwohl kein Text mehr da ist, muss eine weitere Zeile
535 		// formatiert werden, weil auch leere Zeilen einem Fly
536 		// ohne Umlauf ausweichen muessen.
537 		if( bFullLine && rInf.GetIdx() == rInf.GetTxt().Len() )
538 		{
539 			rInf.SetNewLine( sal_True );
540 			// 8221: Dummies erkennt man an Ascent == Height
541             pCurr->SetDummy(sal_True);
542 		}
543 
544 		// aInter wird framelokal
545 		aInter.Pos().X() -= nLeftMar;
546 		SwFlyPortion *pFly = new SwFlyPortion( aInter );
547 		if( bForced )
548 		{
549 			pCurr->SetForcedLeftMargin( sal_True );
550             rInf.ForcedLeftMargin( (sal_uInt16)aInter.Width() );
551 		}
552 
553 		if( bFullLine )
554 		{
555 			// 8110: wir muessen um Einheiten von Zeilenhoehen anwachsen,
556 			// um nebeneinanderliegende Flys mit unterschiedlichen
557 			// Umlaufattributen angemessen zu umfliessen.
558 			// Die letzte ausweichende Zeile, sollte in der Hoehe angepasst
559 			// sein, damit nicht der Eindruck von "Rahmenabstaenden" aufkommt.
560 			// 8221: Wichtig ist, dass Ascent == Height ist, weil die FlyPortionWerte
561 			// im CalcLine in pCurr uebertragen werden und IsDummy() darauf
562 			// angewiesen ist.
563 			// Es gibt meines Wissens nur zwei Stellen, in denen DummyLines
564 			// entstehen koennen: hier und in MakeFlyDummies.
565 			// Ausgewertet wird IsDummy() in IsFirstTxtLine() und
566 			// beim Zeilenwandern und im Zusammenhang mit DropCaps.
567 			pFly->Height( KSHORT(aInter.Height()) );
568 
569 			// In nNextTop steckt jetzt die Unterkante des Rahmens, dem wir
570 			// ausweichen oder die Oberkante des naechsten Rahmens, den wir
571 			// beachten muessen. Wir koennen also jetzt getrost bis zu diesem
572 			// Wert anwachsen, so sparen wir einige Leerzeilen.
573             long nNextTop = pTxtFly->GetNextTop();
574             if ( pFrm->IsVertical() )
575                 nNextTop = pFrm->SwitchVerticalToHorizontal( nNextTop );
576             if( nNextTop > aInter.Bottom() )
577 			{
578                 SwTwips nH = nNextTop - aInter.Top();
579 				if( nH < KSHRT_MAX )
580 					pFly->Height( KSHORT( nH ) );
581 			}
582 			if( nAscent < pFly->Height() )
583 				pFly->SetAscent( KSHORT(nAscent) );
584 			else
585 				pFly->SetAscent( pFly->Height() );
586 		}
587 		else
588 		{
589 			if( rInf.GetIdx() == rInf.GetTxt().Len() )
590 			{
591 				// Nicht nHeight nehmen, sonst haben wir einen Riesendescent
592 				pFly->Height( pLast->Height() );
593 				pFly->SetAscent( pLast->GetAscent() );
594 			}
595 			else
596 			{
597 				pFly->Height( KSHORT(aInter.Height()) );
598 				if( nAscent < pFly->Height() )
599 					pFly->SetAscent( KSHORT(nAscent) );
600 				else
601 					pFly->SetAscent( pFly->Height() );
602 			}
603 		}
604 
605 		rInf.SetFly( pFly );
606 
607         if( pFly->Fix() < rInf.Width() )
608 			rInf.Width( pFly->Fix() );
609 
610         GETGRID( pFrm->FindPageFrm() )
611         if ( pGrid )
612         {
613             const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
614             const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();
615 
616             SWRECTFN( pPageFrm )
617 
618             const long nGridOrigin = pBody ?
619                                     (pBody->*fnRect->fnGetPrtLeft)() :
620                                     (pPageFrm->*fnRect->fnGetPrtLeft)();
621 
622 			const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
623             const sal_uInt16 nGridWidth = GETGRIDWIDTH( pGrid, pDoc);	//for textgrid refactor
624 
625             SwTwips nStartX = GetLeftMargin();
626             if ( bVert )
627             {
628                 Point aPoint( nStartX, 0 );
629                 pFrm->SwitchHorizontalToVertical( aPoint );
630                 nStartX = aPoint.Y();
631             }
632 
633             const SwTwips nOfst = nStartX - nGridOrigin;
634             const SwTwips nTmpWidth = rInf.Width() + nOfst;
635 
636             const sal_uLong i = nTmpWidth / nGridWidth + 1;
637 
638             const long nNewWidth = ( i - 1 ) * nGridWidth - nOfst;
639             if ( nNewWidth > 0 )
640                 rInf.Width( (sal_uInt16)nNewWidth );
641             else
642                 rInf.Width( 0 );
643         }
644 	}
645 }
646 
647 /*****************************************************************************
648  * SwTxtFormatter::NewFlyCntPortion
649  * legt eine neue Portion fuer ein zeichengebundenes Objekt an.
650  *****************************************************************************/
651 
652 SwFlyCntPortion *SwTxtFormatter::NewFlyCntPortion( SwTxtFormatInfo &rInf,
653 												   SwTxtAttr *pHint ) const
654 {
655 	SwFlyCntPortion *pRet = 0;
656 	const SwFrm *pFrame = (SwFrm*)pFrm;
657 
658 	SwFlyInCntFrm *pFly;
659 	SwFrmFmt* pFrmFmt = ((SwTxtFlyCnt*)pHint)->GetFlyCnt().GetFrmFmt();
660 	if( RES_FLYFRMFMT == pFrmFmt->Which() )
661 		pFly = ((SwTxtFlyCnt*)pHint)->GetFlyFrm(pFrame);
662 	else
663 		pFly = NULL;
664 	// aBase bezeichnet die dokumentglobale Position,
665 	// ab der die neue Extraportion plaziert wird.
666 	// aBase.X() = Offset in der Zeile,
667 	//			   hinter der aktuellen Portion
668 	// aBase.Y() = LineIter.Y() + Ascent der aktuellen Portion
669 
670 	long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
671     // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
672     //SwLinePortion *pPos = pCurr->GetFirstPortion();
673     //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
674     pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
675 
676 	// Wenn der Ascent des Rahmens groesser als der Ascent der akt. Portion
677 	// ist, wird dieser bei der Base-Berechnung verwendet, sonst wuerde
678 	// der Rahmen zunaechst zu weit nach oben gesetzt, um dann doch wieder
679 	// nach unten zu rutschen und dabei ein Repaint in einem Bereich ausloesen,
680 	// indem er niemals wirklich war.
681     KSHORT nAscent = 0;
682 
683     const bool bTxtFrmVertical = GetInfo().GetTxtFrm()->IsVertical();
684 
685     const bool bUseFlyAscent = pFly && pFly->GetValidPosFlag() &&
686                                0 != ( bTxtFrmVertical ?
687                                       pFly->GetRefPoint().X() :
688                                       pFly->GetRefPoint().Y() );
689 
690     if ( bUseFlyAscent )
691          nAscent = static_cast<sal_uInt16>( Abs( int( bTxtFrmVertical ?
692                                                   pFly->GetRelPos().X() :
693                                                   pFly->GetRelPos().Y() ) ) );
694 
695     // check if be prefer to use the ascent of the last portion:
696     if ( IsQuick() ||
697          !bUseFlyAscent ||
698          nAscent < rInf.GetLast()->GetAscent() )
699     {
700 		nAscent = rInf.GetLast()->GetAscent();
701     }
702     else if( nAscent > nFlyAsc )
703 		nFlyAsc = nAscent;
704 
705 	Point aBase( GetLeftMargin() + rInf.X(), Y() + nAscent );
706     objectpositioning::AsCharFlags nMode = IsQuick() ? AS_CHAR_QUICK : 0;
707 	if( GetMulti() && GetMulti()->HasRotation() )
708 	{
709         nMode |= AS_CHAR_ROTATE;
710 		if( GetMulti()->IsRevers() )
711             nMode |= AS_CHAR_REVERSE;
712 	}
713 
714     Point aTmpBase( aBase );
715     if ( GetInfo().GetTxtFrm()->IsVertical() )
716         GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
717 
718 	if( pFly )
719 	{
720         pRet = new SwFlyCntPortion( *GetInfo().GetTxtFrm(), pFly, aTmpBase,
721                                     nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
722 		// Wir muessen sicherstellen, dass unser Font wieder im OutputDevice
723 		// steht. Es koennte sein, dass der FlyInCnt frisch eingefuegt wurde,
724 		// dann hat GetFlyFrm dazu gefuehrt, dass er neu angelegt wird.
725 		// Dessen Frames werden sofort formatiert, die verstellen den Font
726 		// und schon haben wir den Salat (3322).
727 		rInf.SelectFont();
728 		if( pRet->GetAscent() > nAscent )
729 		{
730 			aBase.Y() = Y() + pRet->GetAscent();
731             nMode |= AS_CHAR_ULSPACE;
732 			if( !rInf.IsTest() )
733                 aTmpBase = aBase;
734                 if ( GetInfo().GetTxtFrm()->IsVertical() )
735                     GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );
736 
737                 pRet->SetBase( *rInf.GetTxtFrm(), aTmpBase, nTmpAscent,
738                                nTmpDescent, nFlyAsc, nFlyDesc, nMode );
739 		}
740 	}
741 	else
742 	{
743         pRet = new SwFlyCntPortion( *rInf.GetTxtFrm(), (SwDrawContact*)pFrmFmt->FindContactObj(),
744            aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
745 	}
746 	return pRet;
747 }
748 
749 
750 
751 /*************************************************************************
752  *						SwTxtFly::SwTxtFly()
753  *************************************************************************/
754 
755 SwTxtFly::SwTxtFly( const SwTxtFly& rTxtFly )
756 {
757 	pPage = rTxtFly.pPage;
758     // --> OD 2006-08-15 #i68520#
759     mpCurrAnchoredObj = rTxtFly.mpCurrAnchoredObj;
760     // <--
761 	pCurrFrm = rTxtFly.pCurrFrm;
762 	pMaster = rTxtFly.pMaster;
763     // --> OD 2006-08-15 #i68520#
764     if( rTxtFly.mpAnchoredObjList )
765 	{
766         mpAnchoredObjList = new SwAnchoredObjList( *(rTxtFly.mpAnchoredObjList) );
767 	}
768 	else
769     {
770         mpAnchoredObjList = NULL;
771     }
772     // <--
773 
774 	bOn = rTxtFly.bOn;
775 	bLeftSide = rTxtFly.bLeftSide;
776 	bTopRule = rTxtFly.bTopRule;
777 }
778 
779 void SwTxtFly::CtorInitTxtFly( const SwTxtFrm *pFrm )
780 {
781     mbIgnoreCurrentFrame = sal_False;
782     mbIgnoreContour = sal_False;
783     // --> OD 2004-12-17 #118809#
784     mbIgnoreObjsInHeaderFooter = sal_False;
785     // <--
786     pPage = pFrm->FindPageFrm();
787 	const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
788     // --> OD 2006-08-15 #i68520#
789     mpCurrAnchoredObj = pTmp;
790     // <--
791 	pCurrFrm = pFrm;
792 	pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
793     // --> OD 2006-08-15 #i68520#
794     mpAnchoredObjList = NULL;
795     // <--
796     // Wenn wir nicht von einem Frame ueberlappt werden, oder wenn
797 	// es gar keine FlyCollection gibt, dann schaltet wir uns fuer immer ab.
798 	// Aber es koennte sein, dass waehrend der Formatierung eine Zeile
799 	// hinzukommt, die in einen Frame hineinragt. Deswegen keine Optimierung
800 	// per bOn = pSortedFlys && IsAnyFrm();
801 	bOn = pPage->GetSortedObjs() != 0;
802 	bTopRule = sal_True;
803 	bLeftSide = sal_False;
804 	nMinBottom = 0;
805 	nIndex = ULONG_MAX;
806 }
807 
808 /*************************************************************************
809  *						SwTxtFly::_GetFrm()
810  *
811  * IN:	dokumentglobal	(rRect)
812  * OUT: framelokal		(return-Wert)
813  * Diese Methode wird waehrend der Formatierung vom LineIter gerufen.
814  * 1. um die naechste FlyPortion vorzubereiten
815  * 2. um nach Aenderung der Zeilenhoehe neue Ueberlappungen festzustellen
816  *************************************************************************/
817 
818 SwRect SwTxtFly::_GetFrm( const SwRect &rRect, sal_Bool bTop ) const
819 {
820 	SwRect aRet;
821 	if( ForEach( rRect, &aRet, sal_True ) )
822 	{
823         SWRECTFN( pCurrFrm )
824 		if( bTop )
825             (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );
826 
827 		// 8110: Bottom nicht immer anpassen.
828         const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
829         const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
830         if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
831              (aRet.*fnRect->fnGetHeight)() < 0 )
832             (aRet.*fnRect->fnSetBottom)( nRectBottom );
833 	}
834 	return aRet;
835 }
836 
837 /*************************************************************************
838  *						SwTxtFly::IsAnyFrm()
839  *
840  * IN: dokumentglobal
841  * fuer die Printarea des aktuellen Frame
842  *
843  * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax)
844  *
845  *************************************************************************/
846 
847 sal_Bool SwTxtFly::IsAnyFrm() const
848 {
849     SWAP_IF_SWAPPED( pCurrFrm )
850 
851 	ASSERT( bOn, "IsAnyFrm: Why?" );
852 	SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
853 		pCurrFrm->Prt().SSize() );
854 
855     const sal_Bool bRet = ForEach( aRect, NULL, sal_False );
856     UNDO_SWAP( pCurrFrm )
857     return bRet;
858 }
859 
860 /*************************************************************************
861  *						SwTxtFly::IsAnyObj()
862  *
863  * IN: dokumentglobal
864  * OUT: sal_True Wenn ein Rahmen oder DrawObj beruecksichtigt werden muss
865  * Nur wenn IsAnyObj sal_False liefert, koennen Optimierungen benutzt werden
866  * wie Paint/FormatEmpty fuer leere Absaetze
867  * und auch das virtuelle Outputdevice.
868  *************************************************************************/
869 
870 sal_Bool SwTxtFly::IsAnyObj( const SwRect &rRect ) const
871 {
872 	ASSERT ( bOn, "SwTxtFly::IsAnyObj: Who's knocking?" );
873 
874 	SwRect aRect( rRect );
875 	if ( aRect.IsEmpty() )
876 		aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
877 						pCurrFrm->Prt().SSize() );
878 
879     const SwSortedObjs *pSorted = pPage->GetSortedObjs();
880 	if( pSorted ) // Eigentlich ist durch bOn sichergestellt, dass es an der
881 	// Seite Objekte gibt, aber wer weiss, wer inzwischen etwas geloescht hat.
882 	{
883 		for ( MSHORT i = 0; i < pSorted->Count(); ++i )
884 		{
885             const SwAnchoredObject* pObj = (*pSorted)[i];
886 
887             const SwRect aBound( pObj->GetObjRectWithSpaces() );
888 
889 			// Optimierung
890             if( pObj->GetObjRect().Left() > aRect.Right() )
891 				continue;
892 
893             // --> OD 2006-08-15 #i68520#
894             if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
895             // <--
896 				return sal_True;
897 		}
898 	}
899 	return sal_False;
900 }
901 
902 const SwCntntFrm* SwTxtFly::_GetMaster()
903 {
904 	pMaster = pCurrFrm;
905 	while( pMaster->IsFollow() )
906 		pMaster = (SwCntntFrm*)pMaster->FindMaster();
907 	return pMaster;
908 }
909 
910 /*************************************************************************
911  *						SwTxtFly::DrawTextOpaque()
912  *
913  * IN: dokumentglobal
914  * DrawTextOpaque() wird von DrawText() gerufen.
915  * Die Clipregions werden so gesetzt, dass nur die Teile ausgegeben werden,
916  * die nicht in den Bereichen von FlyFrms liegen, die undurchsichtig und
917  * ueber dem aktuellen Frame liegen.
918  * Die On-Optimierung uebernimmt DrawText()!
919  *************************************************************************/
920 
921 sal_Bool SwTxtFly::DrawTextOpaque( SwDrawTextInfo &rInf )
922 {
923 	SwSaveClip aClipSave( rInf.GetpOut() );
924 	SwRect aRect( rInf.GetPos(), rInf.GetSize() );
925 	if( rInf.GetSpace() )
926 	{
927 		xub_StrLen nTmpLen = STRING_LEN == rInf.GetLen() ? rInf.GetText().Len() :
928 													  rInf.GetLen();
929 		if( rInf.GetSpace() > 0 )
930 		{
931 			xub_StrLen nSpaceCnt = 0;
932 			const xub_StrLen nEndPos = rInf.GetIdx() + nTmpLen;
933 			for( xub_StrLen nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos )
934 			{
935 				if( CH_BLANK == rInf.GetText().GetChar( nPos ) )
936 					++nSpaceCnt;
937 			}
938 			if( nSpaceCnt )
939 				aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
940 		}
941 		else
942 			aRect.Width( aRect.Width() - nTmpLen * rInf.GetSpace() );
943 	}
944 
945 	if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
946 	{
947 		SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
948 		aRect.Intersection( aClipRect );
949 	}
950 
951 	SwRegionRects aRegion( aRect );
952 
953 	sal_Bool bOpaque = sal_False;
954     // --> OD 2006-08-15 #i68520#
955     const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
956                             ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
957                             : SAL_MAX_UINT32;
958     // <--
959 	ASSERT( !bTopRule, "DrawTextOpaque: Wrong TopRule" );
960 
961     // --> OD 2006-08-15 #i68520#
962     SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
963     if ( bOn && nCount > 0 )
964     // <--
965 	{
966         MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
967 		for( MSHORT i = 0; i < nCount; ++i )
968 		{
969             // --> OD 2006-08-15 #i68520#
970             const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
971             if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
972                 mpCurrAnchoredObj != pTmpAnchoredObj )
973             // <--
974 			{
975                 // --> OD 2006-08-15 #i68520#
976                 const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj);
977                 // <--
978 				if( aRegion.GetOrigin().IsOver( pFly->Frm() ) )
979 				{
980 					const SwFrmFmt *pFmt = pFly->GetFmt();
981 					const SwFmtSurround &rSur = pFmt->GetSurround();
982 					const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
983 						//Nur undurchsichtige und weiter oben liegende.
984                     /// OD 08.10.2002 #103898# - add condition
985                     /// <!(pFly->IsBackgroundTransparent() || pFly->IsShadowTransparent())>
986                     if( !( pFly->IsBackgroundTransparent()
987                            || pFly->IsShadowTransparent() ) &&
988                         SURROUND_THROUGHT == rSur.GetSurround() &&
989                         ( !rSur.IsAnchorOnly() ||
990                           // --> OD 2006-08-15 #i68520#
991                           GetMaster() == pFly->GetAnchorFrm() ||
992                           // <--
993                           ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
994                            (FLY_AT_CHAR != rAnchor.GetAnchorId())
995                           )
996                         ) &&
997                         // --> OD 2006-08-15 #i68520#
998                         pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
999                         nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
1000                         // <--
1001                       )
1002 					{
1003 						//Ausser der Inhalt ist Transparent
1004 						const SwNoTxtFrm *pNoTxt =
1005 								pFly->Lower() && pFly->Lower()->IsNoTxtFrm()
1006 												   ? (SwNoTxtFrm*)pFly->Lower()
1007 												   : 0;
1008 						if ( !pNoTxt ||
1009 							 (!pNoTxt->IsTransparent() && !rSur.IsContour()) )
1010 						{
1011 							bOpaque = sal_True;
1012 							aRegion -= pFly->Frm();
1013 						}
1014 					}
1015 				}
1016 			}
1017 		}
1018 	}
1019 
1020 	Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
1021 	const Point &rOld = rInf.GetPos();
1022 	rInf.SetPos( aPos );
1023 
1024 	if( !bOpaque )
1025 	{
1026 		if( rInf.GetKern() )
1027 			rInf.GetFont()->_DrawStretchText( rInf );
1028 		else
1029 			rInf.GetFont()->_DrawText( rInf );
1030 		rInf.SetPos( rOld );
1031 		return sal_False;
1032 	}
1033 	else if( aRegion.Count() )
1034 	{
1035 		// Was fuer ein Aufwand ...
1036 		SwSaveClip aClipVout( rInf.GetpOut() );
1037 		for( MSHORT i = 0; i < aRegion.Count(); ++i )
1038 		{
1039 			SwRect &rRect = aRegion[i];
1040 			if( rRect != aRegion.GetOrigin() )
1041 				aClipVout.ChgClip( rRect );
1042 			if( rInf.GetKern() )
1043 				rInf.GetFont()->_DrawStretchText( rInf );
1044 			else
1045 				rInf.GetFont()->_DrawText( rInf );
1046 		}
1047 	}
1048 	rInf.SetPos( rOld );
1049 	return sal_True;
1050 }
1051 
1052 /*************************************************************************
1053  *						SwTxtFly::DrawFlyRect()
1054  *
1055  * IN: windowlokal
1056  * Zwei Feinheiten gilt es zu beachten:
1057  * 1) DrawRect() oberhalb des ClipRects sind erlaubt !
1058  * 2) FlyToRect() liefert groessere Werte als die Framedaten !
1059  *************************************************************************/
1060 
1061 void SwTxtFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
1062 		const SwTxtPaintInfo &rInf, sal_Bool bNoGraphic )
1063 {
1064 	SwRegionRects aRegion( rRect );
1065 	ASSERT( !bTopRule, "DrawFlyRect: Wrong TopRule" );
1066     // --> OD 2006-08-15 #i68520#
1067     SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1068     if ( bOn && nCount > 0 )
1069     // <--
1070 	{
1071         MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
1072 		for( MSHORT i = 0; i < nCount; ++i )
1073 		{
1074             // --> OD 2006-08-15 #i68520#
1075             const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
1076             if( mpCurrAnchoredObj != pAnchoredObjTmp &&
1077                 dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp) )
1078             // <--
1079 			{
1080                 // --> OD 2006-08-15 #i68520#
1081                 const SwFmtSurround& rSur = pAnchoredObjTmp->GetFrmFmt().GetSurround();
1082                 // <--
1083 
1084                 // OD 24.01.2003 #106593# - correct clipping of fly frame area.
1085                 // Consider that fly frame background/shadow can be transparent
1086                 // and <SwAlignRect(..)> fly frame area
1087                 // --> OD 2006-08-15 #i68520#
1088                 const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
1089                 // <--
1090                 // --> OD 2005-06-08 #i47804# - consider transparent graphics
1091                 // and OLE objects.
1092                 bool bClipFlyArea =
1093                         ( ( SURROUND_THROUGHT == rSur.GetSurround() )
1094                           // --> OD 2006-08-15 #i68520#
1095                           ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
1096                           // <--
1097                           : !rSur.IsContour() ) &&
1098                         !pFly->IsBackgroundTransparent() &&
1099                         !pFly->IsShadowTransparent() &&
1100                         ( !pFly->Lower() ||
1101                           !pFly->Lower()->IsNoTxtFrm() ||
1102                           !static_cast<const SwNoTxtFrm*>(pFly->Lower())->IsTransparent() );
1103                 // <--
1104                 if ( bClipFlyArea )
1105 				{
1106                     // --> OD 2006-08-15 #i68520#
1107                     SwRect aFly( pAnchoredObjTmp->GetObjRect() );
1108                     // <--
1109                     // OD 24.01.2003 #106593#
1110                     ::SwAlignRect( aFly, pPage->getRootFrm()->GetCurrShell() );
1111 					if( aFly.Width() > 0 && aFly.Height() > 0 )
1112 						aRegion -= aFly;
1113 				}
1114 			}
1115 		}
1116 	}
1117 
1118 	for( MSHORT i = 0; i < aRegion.Count(); ++i )
1119 	{
1120 		if ( bNoGraphic )
1121 			pOut->DrawRect( aRegion[i].SVRect() );
1122 		else
1123 		{
1124 			ASSERT( ((SvxBrushItem*)-1) != rInf.GetBrushItem(),
1125 					"DrawRect: Uninitialized BrushItem!" );
1126 			::DrawGraphic( rInf.GetBrushItem(), pOut, rInf.GetBrushRect(),
1127 					   aRegion[i] );
1128 		}
1129 	}
1130 }
1131 
1132 // --> OD 2004-10-06 #i26945# - change first parameter:
1133 // Now it's the <SwAnchoredObject> instance of the floating screen object
1134 sal_Bool SwTxtFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
1135                            const sal_Bool bInFtn,
1136                            const sal_Bool bInFooterOrHeader )
1137 // <--
1138 {
1139     // --> OD 2006-08-15 #i68520#
1140     // <mpCurrAnchoredObj> is set, if <pCurrFrm> is inside a fly frame
1141     if( _pAnchoredObj != mpCurrAnchoredObj )
1142     // <--
1143 	{
1144         // --> OD 2004-10-06 #i26945#
1145         const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
1146         // <--
1147 		// #102344# Ignore connectors which have one or more connections
1148 		if(pNew && pNew->ISA(SdrEdgeObj))
1149 		{
1150 			if(((SdrEdgeObj*)pNew)->GetConnectedNode(sal_True)
1151 				|| ((SdrEdgeObj*)pNew)->GetConnectedNode(sal_False))
1152 			{
1153 				return sal_False;
1154 			}
1155 		}
1156 
1157         if( ( bInFtn || bInFooterOrHeader ) && bTopRule )
1158         {
1159             // --> OD 2004-10-06 #i26945#
1160             const SwFrmFmt& rFrmFmt = _pAnchoredObj->GetFrmFmt();
1161             const SwFmtAnchor& rNewA = rFrmFmt.GetAnchor();
1162             // <--
1163             if (FLY_AT_PAGE == rNewA.GetAnchorId())
1164             {
1165                 if ( bInFtn )
1166                     return sal_False;
1167 
1168                 if ( bInFooterOrHeader )
1169                 {
1170                     SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() );
1171                     sal_Bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
1172                             aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
1173                     if( bVertPrt )
1174                         return sal_False;
1175                 }
1176             }
1177         }
1178 
1179         // --> OD 2006-08-15 #i68520#
1180         // bEvade: consider pNew, if we are not inside a fly
1181         //         consider pNew, if pNew is lower of <mpCurrAnchoredObj>
1182         sal_Bool bEvade = !mpCurrAnchoredObj ||
1183                           Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);
1184 
1185         if ( !bEvade )
1186 		{
1187             // We are currently inside a fly frame and pNew is not
1188             // inside this fly frame. We can do some more checks if
1189             // we have to consider pNew.
1190 
1191             // If bTopRule is not set, we ignore the frame types.
1192             // We directly check the z-order
1193 			if ( !bTopRule )
1194 				bEvade = sal_True;
1195 			else
1196 			{
1197 				// innerhalb von verketteten Flys wird nur Lowern ausgewichen
1198                 // --> OD 2006-08-15 #i68520#
1199                 const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain();
1200                 // <--
1201 				if ( !rChain.GetPrev() && !rChain.GetNext() )
1202 				{
1203                     // --> OD 2004-10-06 #i26945#
1204                     const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
1205                     // <--
1206                     // --> OD 2006-08-15 #i68520#
1207                     const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor();
1208                     // <--
1209 
1210                     // If <mpCurrAnchoredObj> is anchored as character, its content
1211                     // does not wrap around pNew
1212                     if (FLY_AS_CHAR == rCurrA.GetAnchorId())
1213 						return sal_False;
1214 
1215                     // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
1216                     // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
1217                     // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
1218                     // some more checks
1219                     if (FLY_AT_PAGE == rNewA.GetAnchorId())
1220                     {
1221                         if (FLY_AT_PAGE == rCurrA.GetAnchorId())
1222                         {
1223                             bEvade = sal_True;
1224                         }
1225 						else
1226 							return sal_False;
1227 					}
1228                     else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
1229 						return sal_False; // Seitengebundene weichen nur seitengeb. aus
1230 					else if (FLY_AT_FLY == rNewA.GetAnchorId())
1231 						bEvade = sal_True; // Nicht seitengeb. weichen Rahmengeb. aus
1232 					else if( FLY_AT_FLY == rCurrA.GetAnchorId() )
1233 						return sal_False; // Rahmengebundene weichen abs.geb. nicht aus
1234                     // --> OD 2006-01-30 #i57062#
1235                     // In order to avoid loop situation, it's decided to adjust
1236                     // the wrapping behaviour of content of at-paragraph/at-character
1237                     // anchored objects to one in the page header/footer and
1238                     // the document body --> content of at-paragraph/at-character
1239                     // anchored objects doesn't wrap around each other.
1240 //                    else if( bInFooterOrHeader )
1241 //                        return sal_False;  // In header or footer no wrapping
1242 //                                           // if both bounded at paragraph
1243 //                    else // Zwei Flies mit (auto-)absatzgebunder Verankerung ...
1244 //                    // ... entscheiden nach der Reihenfolge ihrer Anker im Dok.
1245 //                      bEvade = rNewA.GetCntntAnchor()->nNode.GetIndex() <=
1246 //                              rCurrA.GetCntntAnchor()->nNode.GetIndex();
1247                     else
1248                         return sal_False;
1249                     // <--
1250 				}
1251 			}
1252 
1253             // aber: es wird niemals einem hierarchisch untergeordnetem
1254 			// ausgewichen und ausserdem braucht nur bei Ueberlappung
1255 			// ausgewichen werden.
1256             // --> OD 2006-08-15 #i68520#
1257             bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
1258             // <--
1259 			if( bEvade )
1260 			{
1261                 // --> OD 2006-08-15 #i68520#
1262                 SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
1263                 if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
1264                     bEvade = sal_False;
1265                 // <--
1266 			}
1267 		}
1268 
1269         if ( bEvade )
1270 		{
1271             // --> OD 2004-10-06 #i26945#
1272             const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
1273             // <--
1274             ASSERT( FLY_AS_CHAR != rNewA.GetAnchorId(),
1275                     "Don't call GetTop with a FlyInCntFrm" );
1276             if (FLY_AT_PAGE == rNewA.GetAnchorId())
1277 				return sal_True;  // Seitengebundenen wird immer ausgewichen.
1278 
1279 			// Wenn absatzgebundene Flys in einem FlyCnt gefangen sind, so
1280 			// endet deren Einflussbereich an den Grenzen des FlyCnt!
1281 			// Wenn wir aber gerade den Text des FlyCnt formatieren, dann
1282 			// muss er natuerlich dem absatzgebundenen Frm ausweichen!
1283 			// pCurrFrm ist der Anker von pNew?
1284             // --> OD 2004-10-06 #i26945#
1285             const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
1286             // <--
1287 			if( pTmp == pCurrFrm )
1288 				return sal_True;
1289 			if( pTmp->IsTxtFrm() && ( pTmp->IsInFly() || pTmp->IsInFtn() ) )
1290 			{
1291                 // --> OD 2004-10-06 #i26945#
1292                 Point aPos = _pAnchoredObj->GetObjRect().Pos();
1293                 // <--
1294 				pTmp = GetVirtualUpper( pTmp, aPos );
1295 			}
1296             // --> OD 2004-10-06 #i26945#
1297             // --> OD 2004-11-29 #115759#
1298             // If <pTmp> is a text frame inside a table, take the upper
1299             // of the anchor frame, which contains the anchor position.
1300             else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() )
1301             {
1302                 pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
1303                                 ->GetAnchorFrmContainingAnchPos()->GetUpper();
1304             }
1305             // <--
1306             // --> OD 2004-05-13 #i28701# - consider all objects in same context,
1307             // if wrapping style is considered on object positioning.
1308             // Thus, text will wrap around negative positioned objects.
1309             // --> OD 2004-08-25 #i3317# - remove condition on checking,
1310             // if wrappings style is considered on object postioning.
1311             // Thus, text is wrapping around negative positioned objects.
1312             // --> OD 2004-10-20 #i35640# - no consideration of negative
1313             // positioned objects, if wrapping style isn't considered on
1314             // object position and former text wrapping is applied.
1315             // This condition is typically for documents imported from the
1316             // OpenOffice.org file format.
1317             const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
1318             if ( (  pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
1319                    !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) &&
1320                  ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
1321             {
1322                 return sal_True;
1323             }
1324             // <--
1325 
1326             const SwFrm* pHeader = 0;
1327             if ( pCurrFrm->GetNext() != pTmp &&
1328                  ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
1329                    // --> #i13832#, #i24135# wrap around objects in page header
1330                    ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
1331                      0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
1332                      !pHeader->IsFooterFrm() &&
1333                      pCurrFrm->IsInDocBody() ) ) )
1334                    // <--
1335 			{
1336 				if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
1337 					return sal_True;
1338 
1339                 // Compare indices:
1340 				// Den Index des anderen erhalten wir immer ueber das Ankerattr.
1341 				sal_uLong nTmpIndex = rNewA.GetCntntAnchor()->nNode.GetIndex();
1342 				// Jetzt wird noch ueberprueft, ob der aktuelle Absatz vor dem
1343 				// Anker des verdraengenden Objekts im Text steht, dann wird
1344 				// nicht ausgewichen.
1345 				// Der Index wird moeglichst ueber einen SwFmtAnchor ermittelt,
1346 				// da sonst recht teuer.
1347 				if( ULONG_MAX == nIndex )
1348 					nIndex = pCurrFrm->GetNode()->GetIndex();
1349 
1350 				if( nIndex >= nTmpIndex )
1351 					return sal_True;
1352 			}
1353 		}
1354 	}
1355     return sal_False;
1356 }
1357 // --> OD 2006-08-15 #i68520#
1358 struct AnchoredObjOrder
1359 {
1360     sal_Bool mbR2L;
1361     SwRectFn mfnRect;
1362 
1363     AnchoredObjOrder( const sal_Bool bR2L,
1364                        SwRectFn fnRect )
1365         : mbR2L( bR2L ),
1366           mfnRect( fnRect )
1367     {}
1368 
1369     bool operator()( const SwAnchoredObject* pListedAnchoredObj,
1370                      const SwAnchoredObject* pNewAnchoredObj )
1371     {
1372         const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
1373         const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
1374         if ( ( mbR2L &&
1375                ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
1376                  (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
1377              ( !mbR2L &&
1378                ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
1379                  (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
1380         {
1381             SwTwips nTopDiff =
1382                 (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
1383                                     (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
1384             if ( nTopDiff == 0 &&
1385                  ( ( mbR2L &&
1386                      ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
1387                        (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
1388                    ( !mbR2L &&
1389                      ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
1390                        (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
1391             {
1392                 return true;
1393             }
1394             else if ( nTopDiff > 0 )
1395             {
1396                 return true;
1397             }
1398         }
1399         else if ( ( mbR2L &&
1400                     ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
1401                       (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
1402                   ( !mbR2L &&
1403                     ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
1404                       (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
1405         {
1406             return true;
1407         }
1408 
1409         return false;
1410     }
1411 };
1412 
1413 // --> OD 2006-08-15 #i68520#
1414 SwAnchoredObjList* SwTxtFly::InitAnchoredObjList()
1415 {
1416 	ASSERT( pCurrFrm, "InitFlyList: No Frame, no FlyList" );
1417     // --> OD 2006-08-15 #i68520#
1418     ASSERT( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
1419     // <--
1420 
1421     SWAP_IF_SWAPPED( pCurrFrm )
1422 
1423     const SwSortedObjs *pSorted = pPage->GetSortedObjs();
1424     const sal_uInt32 nCount = pSorted ? pSorted->Count() : 0;
1425     // --> #108724# Page header/footer content doesn't have to wrap around
1426     //              floating screen objects
1427     const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
1428     const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
1429     // --> OD 2005-01-12 #i40155# - check, if frame is marked not to wrap
1430     const sal_Bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
1431                                     ( !pCurrFrm->IsInFtn() && !bFooterHeader ) ) &&
1432                                       !SwLayouter::FrmNotToWrap( *pCurrFrm->GetTxtNode()->getIDocumentLayoutAccess(), *pCurrFrm );
1433     // <--
1434 
1435     bOn = sal_False;
1436 
1437 	if( nCount && bWrapAllowed )
1438 	{
1439         // --> OD 2006-08-15 #i68520#
1440         mpAnchoredObjList = new SwAnchoredObjList();
1441         // <--
1442 
1443         // --> OD 2004-06-18 #i28701# - consider complete frame area for new
1444         // text wrapping
1445         SwRect aRect;
1446         if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) )
1447         {
1448             aRect = pCurrFrm->Prt();
1449             aRect += pCurrFrm->Frm().Pos();
1450         }
1451         else
1452         {
1453             aRect = pCurrFrm->Frm();
1454         }
1455 		// Wir machen uns etwas kleiner als wir sind,
1456 		// damit Ein-Twip-Ueberlappungen ignoriert werden. (#49532)
1457         SWRECTFN( pCurrFrm )
1458         const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
1459         const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
1460         const sal_Bool bR2L = pCurrFrm->IsRightToLeft();
1461 
1462         const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess();
1463 
1464         for( sal_uInt32 i = 0; i < nCount; i++ )
1465 		{
1466             // --> OD 2006-08-15 #i68520#
1467 //            SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
1468 //            const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
1469 
1470 //            // OD 2004-01-15 #110582# - do not consider hidden objects
1471 //            // OD 2004-05-13 #i28701# - check, if object has to be considered
1472 //            // for text wrap.
1473 //            if ( !pDoc->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
1474 //                 !pAnchoredObj->ConsiderForTextWrap() ||
1475 //                 nRight < (aBound.*fnRect->fnGetLeft)() ||
1476 //                 (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
1477 //                                     (aBound.*fnRect->fnGetBottom)() ) > 0 ||
1478 //                 nLeft > (aBound.*fnRect->fnGetRight)() ||
1479 //                 // --> OD 2004-12-17 #118809# - If requested, do not consider
1480 //                 // objects in page header|footer for text frames not in page
1481 //                 // header|footer. This is requested for the calculation of
1482 //                 // the base offset for objects <SwTxtFrm::CalcBaseOfstForFly()>
1483 //                 ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
1484 //                   pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) ||
1485 //                 // <--
1486 //                 // --> FME 2004-07-14 #i20505# Do not consider oversized objects
1487 //                 (aBound.*fnRect->fnGetHeight)() >
1488 //                 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
1489 //                 // <--
1490 //            {
1491 //              continue;
1492 //            }
1493             SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
1494             if ( !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
1495                  !pAnchoredObj->ConsiderForTextWrap() ||
1496                  ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
1497                    pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
1498             {
1499                 continue;
1500             }
1501 
1502             const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
1503             if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
1504                  (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
1505                                      (aBound.*fnRect->fnGetBottom)() ) > 0 ||
1506                  nLeft > (aBound.*fnRect->fnGetRight)() ||
1507                  (aBound.*fnRect->fnGetHeight)() >
1508                                     2 * (pPage->Frm().*fnRect->fnGetHeight)() )
1509             {
1510                 continue;
1511             }
1512             // <--
1513 
1514             // --> OD 2004-10-06 #i26945# - pass <pAnchoredObj> to method
1515             // <GetTop(..)> instead of only the <SdrObject> instance of the
1516             // anchored object
1517             if ( GetTop( pAnchoredObj, pCurrFrm->IsInFtn(), bFooterHeader ) )
1518             // <--
1519 			{
1520                 // OD 11.03.2003 #107862# - adjust insert position:
1521                 // overlapping objects should be sorted from left to right and
1522                 // inside left to right sorting from top to bottom.
1523                 // If objects on the same position are found, they are sorted
1524                 // on its width.
1525                 // --> OD 2006-08-15 #i68520#
1526 //                sal_uInt16 nPos = pFlyList->Count();
1527 //                while ( nPos )
1528 //                {
1529 //                    SdrObject* pTmpObj = (*pFlyList)[ --nPos ];
1530 //                    const SwRect aBoundRectOfTmpObj( GetBoundRect( pTmpObj ) );
1531 //                    if ( ( bR2L &&
1532 //                           ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ==
1533 //                             (aBound.*fnRect->fnGetRight)() ) ) ||
1534 //                         ( !bR2L &&
1535 //                           ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ==
1536 //                             (aBound.*fnRect->fnGetLeft)() ) ) )
1537 //                    {
1538 //                        SwTwips nTopDiff =
1539 //                            (*fnRect->fnYDiff)( (aBound.*fnRect->fnGetTop)(),
1540 //                                                (aBoundRectOfTmpObj.*fnRect->fnGetTop)() );
1541 //                        if ( nTopDiff == 0 &&
1542 //                             ( ( bR2L &&
1543 //                                 ( (aBound.*fnRect->fnGetLeft)() >
1544 //                                   (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ) ) ||
1545 //                               ( !bR2L &&
1546 //                                 ( (aBound.*fnRect->fnGetRight)() <
1547 //                                   (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ) ) ) )
1548 //                        {
1549 //                            ++nPos;
1550 //                            break;
1551 //                        }
1552 //                        else if ( nTopDiff > 0 )
1553 //                        {
1554 //                            ++nPos;
1555 //                            break;
1556 //                        }
1557 //                    }
1558 //                    else if ( ( bR2L &&
1559 //                                ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() >
1560 //                                  (aBound.*fnRect->fnGetRight)() ) ) ||
1561 //                              ( !bR2L &&
1562 //                                ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() <
1563 //                                  (aBound.*fnRect->fnGetLeft)() ) ) )
1564 //                    {
1565 //                        ++nPos;
1566 //                        break;
1567 //                    }
1568 //                }
1569 //                SdrObject* pSdrObj = pAnchoredObj->DrawObj();
1570 //                pFlyList->C40_INSERT( SdrObject, pSdrObj, nPos );
1571                 {
1572                     SwAnchoredObjList::iterator aInsPosIter =
1573                             std::lower_bound( mpAnchoredObjList->begin(),
1574                                               mpAnchoredObjList->end(),
1575                                               pAnchoredObj,
1576                                               AnchoredObjOrder( bR2L, fnRect ) );
1577 
1578                     mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
1579                 }
1580                 // <--
1581 
1582                 const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
1583                 // --> OD 2006-08-15 #i68520#
1584                 if ( rFlyFmt.IsAnchorOnly() &&
1585                      pAnchoredObj->GetAnchorFrm() == GetMaster() )
1586                 // <--
1587 				{
1588                     const SwFmtVertOrient &rTmpFmt =
1589                                     pAnchoredObj->GetFrmFmt().GetVertOrient();
1590                     if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
1591                         nMinBottom = ( bVert && nMinBottom ) ?
1592                                      Min( nMinBottom, aBound.Left() ) :
1593                                      Max( nMinBottom, (aBound.*fnRect->fnGetBottom)() );
1594 				}
1595 
1596 				bOn = sal_True;
1597 			}
1598 		}
1599 		if( nMinBottom )
1600 		{
1601             SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
1602             if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
1603 				nMinBottom = nMax;
1604 		}
1605 	}
1606 	else
1607     {
1608         // --> OD 2006-08-15 #i68520#
1609         mpAnchoredObjList = new SwAnchoredObjList();
1610         // <--
1611     }
1612 
1613     UNDO_SWAP( pCurrFrm )
1614 
1615     // --> OD 2006-08-15 #i68520#
1616     return mpAnchoredObjList;
1617     // <--
1618 }
1619 // <--
1620 
1621 SwTwips SwTxtFly::CalcMinBottom() const
1622 {
1623 	SwTwips nRet = 0;
1624     const SwSortedObjs *pDrawObj = GetMaster()->GetDrawObjs();
1625     const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0;
1626 	if( nCount )
1627 	{
1628 		SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
1629         for( sal_uInt32 i = 0; i < nCount; i++ )
1630 		{
1631             SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
1632             const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
1633 			if( rFlyFmt.IsAnchorOnly() )
1634 			{
1635                 const SwFmtVertOrient &rTmpFmt =
1636                                     pAnchoredObj->GetFrmFmt().GetVertOrient();
1637                 if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
1638 				{
1639                     const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
1640 					if( aBound.Top() < nEndOfFrm )
1641 						nRet = Max( nRet, aBound.Bottom() );
1642 				}
1643 			}
1644 		}
1645 		SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
1646 					   pCurrFrm->GetUpper()->Prt().Bottom();
1647 		if( nRet > nMax )
1648 			nRet = nMax;
1649 	}
1650 	return nRet;
1651 }
1652 
1653 /*************************************************************************
1654  * Hier erfolgt die Berechnung der Kontur ...
1655  * CalcBoundRect(..) und andere
1656  *************************************************************************/
1657 
1658 /*************************************************************************
1659  * class SwContourCache
1660  *************************************************************************/
1661 
1662 SwContourCache::SwContourCache() :
1663     nPntCnt( 0 ), nObjCnt( 0 )
1664 {
1665 	memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) );
1666 	memset( pTextRanger, 0, sizeof(pTextRanger) );
1667 }
1668 
1669 SwContourCache::~SwContourCache()
1670 {
1671 	for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
1672 		;
1673 }
1674 
1675 void SwContourCache::ClrObject( MSHORT nPos )
1676 {
1677 	ASSERT( pTextRanger[ nPos ], "ClrObject: Allready cleared. Good Bye!" );
1678 	nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
1679 	delete pTextRanger[ nPos ];
1680 	--nObjCnt;
1681 	memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1,
1682 			 ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
1683 	memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
1684 			 ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
1685 }
1686 
1687 void ClrContourCache( const SdrObject *pObj )
1688 {
1689 	if( pContourCache && pObj )
1690 		for( MSHORT i = 0; i < pContourCache->GetCount(); ++i )
1691 			if( pObj == pContourCache->GetObject( i ) )
1692 			{
1693 				pContourCache->ClrObject( i );
1694 				break;
1695 			}
1696 }
1697 
1698 void ClrContourCache()
1699 {
1700 	if( pContourCache )
1701 	{
1702 		for( MSHORT i = 0; i < pContourCache->GetCount();
1703 			 delete pContourCache->pTextRanger[ i++ ] )
1704 			 ;
1705 		pContourCache->nObjCnt = 0;
1706 		pContourCache->nPntCnt = 0;
1707 	}
1708 }
1709 
1710 /*************************************************************************
1711  * SwContourCache::CalcBoundRect
1712  * berechnet das Rechteck, welches vom Objekt in der angegebenen Zeile
1713  * ueberdeckt wird.
1714  * Bei _nicht_ konturumflossenen Objekten ist dies einfach die Ueber-
1715  * lappung von BoundRect (inkl. Abstand!) und Zeile,
1716  * bei Konturumfluss wird das Polypolygon des Objekts abgeklappert
1717  *************************************************************************/
1718 // --> OD 2006-08-15 #i68520#
1719 const SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
1720                                             const SwRect &rLine,
1721                                             const SwTxtFrm* pFrm,
1722                                             const long nXPos,
1723                                             const sal_Bool bRight )
1724 {
1725     SwRect aRet;
1726     const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
1727 	if( pFmt->GetSurround().IsContour() &&
1728         ( !pAnchoredObj->ISA(SwFlyFrm) ||
1729           ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
1730             static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) )
1731 	{
1732         aRet = pAnchoredObj->GetObjRectWithSpaces();
1733 		if( aRet.IsOver( rLine ) )
1734 		{
1735 			if( !pContourCache )
1736 				pContourCache = new SwContourCache;
1737 
1738             aRet = pContourCache->ContourRect(
1739                     pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
1740 		}
1741 		else
1742 			aRet.Width( 0 );
1743 	}
1744 	else
1745 	{
1746         aRet = pAnchoredObj->GetObjRectWithSpaces();
1747 	}
1748 
1749 	return aRet;
1750 }
1751 // <--
1752 
1753 const SwRect SwContourCache::ContourRect( const SwFmt* pFmt,
1754     const SdrObject* pObj, const SwTxtFrm* pFrm, const SwRect &rLine,
1755     const long nXPos, const sal_Bool bRight )
1756 {
1757 	SwRect aRet;
1758 	MSHORT nPos = 0; // Suche im Cache ...
1759 	while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
1760 		++nPos;
1761 	if( GetCount() == nPos ) // nicht gefunden
1762 	{
1763 		if( nObjCnt == POLY_CNT )
1764 		{
1765 			nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
1766 			delete pTextRanger[ nObjCnt ];
1767 		}
1768 		::basegfx::B2DPolyPolygon aPolyPolygon;
1769 		::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;
1770 
1771 		if ( pObj->ISA(SwVirtFlyDrawObj) )
1772 		{
1773 			// Vorsicht #37347: Das GetContour() fuehrt zum Laden der Grafik,
1774 			// diese aendert dadurch ggf. ihre Groesse, ruft deshalb ein
1775 			// ClrObject() auf.
1776 			PolyPolygon aPoly;
1777 			if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) )
1778 				aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)->
1779 									 GetFlyFrm()->Frm().SVRect() );
1780 			aPolyPolygon.clear();
1781 			aPolyPolygon.append(aPoly.getB2DPolyPolygon());
1782 		}
1783 		else
1784 		{
1785             if( !pObj->ISA( E3dObject ) )
1786 			{
1787 				aPolyPolygon = pObj->TakeXorPoly();
1788 			}
1789 
1790 			::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour());
1791 			pPolyPolygon = new ::basegfx::B2DPolyPolygon(aContourPoly);
1792 		}
1793 		const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace();
1794 		const SvxULSpaceItem &rULSpace = pFmt->GetULSpace();
1795 		memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
1796 		memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
1797 		pSdrObj[ 0 ] = pObj; // Wg. #37347 darf das Object erst nach dem
1798 							 // GetContour() eingetragen werden.
1799         pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
1800             (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(),
1801             pFmt->GetSurround().IsOutside(), sal_False, pFrm->IsVertical() );
1802         pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
1803 		pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );
1804 
1805 		delete pPolyPolygon;
1806 		// UPPER_LOWER_TEST
1807 #ifdef DBG_UTIL
1808         const ViewShell* pTmpViewShell = pFmt->GetDoc()->GetCurrentViewShell();
1809         if( pTmpViewShell )
1810 		{
1811             sal_Bool bT2 = pTmpViewShell->GetViewOptions()->IsTest2();
1812             sal_Bool bT6 = pTmpViewShell->GetViewOptions()->IsTest6();
1813 			if( bT2 || bT6 )
1814 			{
1815 				if( bT2 )
1816 					pTextRanger[ 0 ]->SetFlag7( sal_True );
1817 				else
1818 					pTextRanger[ 0 ]->SetFlag6( sal_True );
1819 			}
1820 		}
1821 #endif
1822 		nPntCnt += pTextRanger[ 0 ]->GetPointCount();
1823 		while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
1824 		{
1825 			nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
1826 			delete pTextRanger[ nObjCnt ];
1827 		}
1828 	}
1829 	else if( nPos )
1830 	{
1831 		const SdrObject* pTmpObj = pSdrObj[ nPos ];
1832 		TextRanger* pTmpRanger = pTextRanger[ nPos ];
1833 		memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nPos * sizeof( SdrObject* ) );
1834 		memmove( pTextRanger + 1, pTextRanger, nPos * sizeof( TextRanger* ) );
1835 		pSdrObj[ 0 ] = pTmpObj;
1836 		pTextRanger[ 0 ] = pTmpRanger;
1837 	}
1838     SWRECTFN( pFrm )
1839     long nTmpTop = (rLine.*fnRect->fnGetTop)();
1840     // fnGetBottom is top + height
1841     long nTmpBottom = (rLine.*fnRect->fnGetBottom)();
1842 
1843     Range aRange( Min( nTmpTop, nTmpBottom ), Max( nTmpTop, nTmpBottom ) );
1844 
1845 	SvLongs *pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );
1846 
1847 	MSHORT nCount;
1848 	if( 0 != ( nCount = pTmp->Count() ) )
1849 	{
1850 		MSHORT nIdx = 0;
1851         while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
1852 			++nIdx;
1853 		sal_Bool bOdd = nIdx % 2 ? sal_True : sal_False;
1854 		sal_Bool bSet = sal_True;
1855 		if( bOdd )
1856 			--nIdx; // innerhalb eines Intervalls
1857         else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
1858 		{
1859 			if( nIdx )
1860 				nIdx -= 2; // ein Intervall nach links gehen
1861 			else
1862 				bSet = sal_False; // vor dem erstem Intervall
1863 		}
1864 
1865 		if( bSet && nIdx < nCount )
1866 		{
1867             (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
1868                                                (rLine.*fnRect->fnGetHeight)() );
1869             (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
1870             (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
1871 		}
1872 	}
1873 	return aRet;
1874 }
1875 
1876 /*************************************************************************
1877  *						SwContourCache::ShowContour()
1878  * zeichnet die PolyPolygone des Caches zu Debugzwecken.
1879  *************************************************************************/
1880 #ifdef DBG_UTIL
1881 
1882 void SwContourCache::ShowContour( OutputDevice* pOut, const SdrObject* pObj,
1883 	const Color& rClosedColor, const Color& rOpenColor )
1884 {
1885 	MSHORT nPos = 0; // Suche im Cache ...
1886 	while( nPos < POLY_CNT && pObj != pSdrObj[ nPos ] )
1887 		++nPos;
1888 	if( POLY_CNT != nPos )
1889 	{
1890 		const PolyPolygon* pPol = pTextRanger[ nPos ]->GetLinePolygon();
1891 		if( !pPol )
1892 			pPol = &(pTextRanger[ nPos ]->GetPolyPolygon());
1893 		for( MSHORT i = 0; i < pPol->Count(); ++i )
1894 		{
1895 			pOut->SetLineColor( rOpenColor );
1896 			const Polygon& rPol = (*pPol)[ i ];
1897 			MSHORT nCount = rPol.GetSize();
1898 			if( nCount > 1 && rPol[ 0 ] == rPol[ nCount - 1 ] )
1899 				pOut->SetLineColor( rClosedColor );
1900 			pOut->DrawPolygon( rPol );
1901 		}
1902 #if OSL_DEBUG_LEVEL > 1
1903 		static KSHORT nRadius = 0;
1904 		if( nRadius )
1905 		{
1906 			KSHORT nHalf = nRadius / 2;
1907 			Size aSz( nRadius, nRadius );
1908 			for( MSHORT i = 0; i < pPol->Count(); ++i )
1909 			{
1910 				const Polygon& rPol = (*pPol)[ i ];
1911 				MSHORT nCount = rPol.GetSize();
1912 				for( MSHORT k = 0; k < nCount; ++k )
1913 				{
1914 					Point aPt( rPol[ k ] );
1915 					aPt.X() -= nHalf;
1916 					aPt.Y() -= nHalf;
1917 					Rectangle aTmp( aPt, aSz );
1918 					pOut->DrawEllipse( aTmp );
1919 				}
1920 			}
1921 		}
1922 #endif
1923 	}
1924 }
1925 #endif
1926 
1927 /*************************************************************************
1928  *						SwTxtFly::ShowContour()
1929  * zeichnet die PolyPolygone des Caches zu Debugzwecken.
1930  *************************************************************************/
1931 #ifdef DBG_UTIL
1932 
1933 void SwTxtFly::ShowContour( OutputDevice* pOut )
1934 {
1935 	MSHORT nFlyCount;
1936     if( bOn && ( 0 != ( nFlyCount = static_cast<sal_uInt16>(GetAnchoredObjList()->size() ) ) ) )
1937 	{
1938 		Color aRedColor( COL_LIGHTRED );
1939 		Color aGreenColor( COL_LIGHTGREEN );
1940 		Color aSaveColor( pOut->GetLineColor() );
1941 		for( MSHORT j = 0; j < nFlyCount; ++j )
1942 		{
1943             const SwAnchoredObject* pObj = (*mpAnchoredObjList)[ j ];
1944             if( !pObj->GetFrmFmt().GetSurround().IsContour() )
1945 			{
1946                 Rectangle aRect = pObj->GetObjRectWithSpaces().SVRect();
1947 				pOut->DrawRect( aRect );
1948 				continue;
1949 			}
1950             pContourCache->ShowContour( pOut, pObj->GetDrawObj(), aRedColor, aGreenColor );
1951 		}
1952 		pOut->SetLineColor( aSaveColor );
1953 	}
1954 }
1955 #endif
1956 
1957 /*************************************************************************
1958  *						SwTxtFly::ForEach()
1959  *
1960  * sucht nach dem ersten Objekt, welches mit dem Rechteck ueberlappt
1961  *
1962  *************************************************************************/
1963 
1964 sal_Bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, sal_Bool bAvoid ) const
1965 {
1966     SWAP_IF_SWAPPED( pCurrFrm )
1967 
1968 	sal_Bool bRet = sal_False;
1969     // --> OD 2006-08-15 #i68520#
1970     SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
1971     if ( bOn && nCount > 0 )
1972     // <--
1973 	{
1974         for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
1975 		{
1976             // --> OD 2006-08-15 #i68520#
1977             const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];
1978 
1979             SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
1980             // <--
1981 
1982             // Optimierung
1983             SWRECTFN( pCurrFrm )
1984             if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
1985 				break;
1986             // --> OD 2006-08-15 #i68520#
1987             if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
1988             // <--
1989 			{
1990                 // --> OD 2006-08-15 #i68520#
1991                 const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) );
1992                 const SwFmtSurround &rSur = pFmt->GetSurround();
1993                 // <--
1994 				if( bAvoid )
1995 				{
1996 					// Wenn der Text drunter durchlaeuft, bleibt die
1997 					// Formatierung unbeeinflusst. Im LineIter::DrawText()
1998 					// muessen "nur" geschickt die ClippingRegions gesetzt werden ...
1999 					const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
2000 					if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
2001 						  ( !rSur.IsAnchorOnly() ||
2002                             // --> OD 2006-08-15 #i68520#
2003                             GetMaster() == pAnchoredObj->GetAnchorFrm() ||
2004                             // <--
2005                             ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
2006                              (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
2007 						|| aRect.Top() == WEIT_WECH )
2008 						continue;
2009 				}
2010 
2011                 // --> OD 2006-01-20 #i58642#
2012                 // Compare <GetMaster()> instead of <pCurrFrm> with the anchor
2013                 // frame of the anchored object, because a follow frame have
2014                 // to ignore the anchored objects of its master frame.
2015                 // Note: Anchored objects are always registered at the master
2016                 //       frame, exception are as-character anchored objects,
2017                 //       but these aren't handled here.
2018                 // --> OD 2006-08-15 #i68520#
2019                 if ( mbIgnoreCurrentFrame &&
2020                      GetMaster() == pAnchoredObj->GetAnchorFrm() )
2021                     continue;
2022                 // <--
2023 
2024 				if( pRect )
2025 				{
2026                     // --> OD 2006-08-15 #i68520#
2027                     SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
2028                     // <--
2029 					if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
2030 						continue;
2031                     if( !bRet || (
2032                         ( !pCurrFrm->IsRightToLeft() &&
2033                           ( (aFly.*fnRect->fnGetLeft)() <
2034                             (pRect->*fnRect->fnGetLeft)() ) ) ||
2035                         ( pCurrFrm->IsRightToLeft() &&
2036                           ( (aFly.*fnRect->fnGetRight)() >
2037                             (pRect->*fnRect->fnGetRight)() ) ) ) )
2038 						*pRect = aFly;
2039 					if( rSur.IsContour() )
2040 					{
2041 						bRet = sal_True;
2042 						continue;
2043 					}
2044 				}
2045 				bRet = sal_True;
2046 				break;
2047 			}
2048 		}
2049 	}
2050 
2051     UNDO_SWAP( pCurrFrm )
2052 
2053 	return bRet;
2054 }
2055 
2056 /*************************************************************************
2057  *						SwTxtFly::GetPos()
2058  *
2059  * liefert die Position im sorted Array zurueck
2060  *************************************************************************/
2061 
2062 // --> OD 2006-08-15 #i68520#
2063 SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
2064 {
2065     SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
2066     SwAnchoredObjList::size_type nRet = 0;
2067     while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
2068         ++nRet;
2069     return nRet;
2070 }
2071 // <--
2072 
2073 /*************************************************************************
2074  *						SwTxtFly::CalcRightMargin()
2075  *
2076  * pObj ist das Object, der uns gerade ueberlappt.
2077  * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird.
2078  * Der rechte Rand ist der rechte Rand oder
2079  * er wird durch das naechste Object, welches in die Zeile ragt, bestimmt.
2080  *************************************************************************/
2081 // --> OD 2006-08-15 #i68520#
2082 void SwTxtFly::CalcRightMargin( SwRect &rFly,
2083                                 SwAnchoredObjList::size_type nFlyPos,
2084                                 const SwRect &rLine ) const
2085 {
2086 	// Normalerweise ist der rechte Rand der rechte Rand der Printarea.
2087     ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
2088             "SwTxtFly::CalcRightMargin with swapped frame" )
2089     SWRECTFN( pCurrFrm )
2090     // --> OD 2004-12-14 #118796# - correct determination of right of printing area
2091     SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
2092     // <--
2093     SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
2094 	SwRect aLine( rLine );
2095     (aLine.*fnRect->fnSetRight)( nRight );
2096     (aLine.*fnRect->fnSetLeft)( (rFly.*fnRect->fnGetLeft)() );
2097 
2098 	// Es koennte aber sein, dass in die gleiche Zeile noch ein anderes
2099 	// Object hineinragt, welches _ueber_ uns liegt.
2100 	// Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden
2101 	// unsichtbar, das heisst, dass sie bei der Berechnung der Raender
2102 	// anderer Flys ebenfalls nicht auffallen.
2103 	// 3301: pNext->Frm().IsOver( rLine ) ist noetig
2104     // --> OD 2006-08-15 #i68520#
2105     SwSurround eSurroundForTextWrap;
2106     // <--
2107 
2108 	sal_Bool bStop = sal_False;
2109     // --> OD 2006-08-15 #i68520#
2110     SwAnchoredObjList::size_type nPos = 0;
2111     // <--
2112 
2113     // --> OD 2006-08-15 #i68520#
2114     while( nPos < mpAnchoredObjList->size() && !bStop )
2115     // <--
2116 	{
2117 		if( nPos == nFlyPos )
2118 		{
2119 			++nPos;
2120 			continue;
2121 		}
2122         // --> OD 2006-08-15 #i68520#
2123         const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
2124         if ( pNext == mpCurrAnchoredObj )
2125 			continue;
2126         eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
2127         if( SURROUND_THROUGHT == eSurroundForTextWrap )
2128 			continue;
2129         // <--
2130 
2131         const SwRect aTmp( SwContourCache::CalcBoundRect
2132                 ( pNext, aLine, pCurrFrm, nFlyRight, sal_True ) );
2133         SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
2134 
2135 		// Optimierung:
2136 		// In nNextTop wird notiert, an welcher Y-Positon mit Aenderung der
2137 		// Rahmenverhaeltnisse gerechnet werden muss. Dies dient dazu, dass,
2138 		// obwohl nur die Rahmen in der aktuellen Zeilenhoehe betrachtet werden,
2139 		// bei Rahmen ohne Umlauf die Zeilenhoehe so erhoeht wird, dass mit einer
2140 		// einzigen Zeile die Unterkante das Rahmens oder ggf. die Oberkante des
2141 		// naechsten Rahmen erreicht wird.
2142 		// Insbesondere bei HTML-Dokumenten kommen oft (Dummy-)Absaetze in einer
2143 		// 2-Pt.-Schrift vor, bis diese einem groesseren Rahmen ausgewichen sind,
2144 		// erforderte es frueher Unmengen von Leerzeilen.
2145         const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
2146         if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 )
2147 		{
2148             if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 )
2149                 SetNextTop( nTmpTop ); // Die Oberkante des "naechsten" Rahmens
2150 		}
2151         else if( ! (aTmp.*fnRect->fnGetWidth)() ) // Typisch fuer Objekte mit Konturumlauf
2152 		{   // Bei Objekten mit Konturumlauf, die vor der aktuellen Zeile beginnen
2153 			// und hinter ihr enden, trotzdem aber nicht mit ihr ueberlappen,
2154 			// muss die Optimierung ausgeschaltet werden, denn bereits in der
2155 			// naechsten Zeile kann sich dies aendern.
2156             if( ! (aTmp.*fnRect->fnGetHeight)() ||
2157                 (*fnRect->fnYDiff)( (aTmp.*fnRect->fnGetBottom)(),
2158                                     (aLine.*fnRect->fnGetTop)() ) > 0 )
2159 				SetNextTop( 0 );
2160 		}
2161 		if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
2162 		{
2163 			nFlyRight = nTmpRight;
2164             if( SURROUND_RIGHT == eSurroundForTextWrap ||
2165                 SURROUND_PARALLEL == eSurroundForTextWrap )
2166 			{
2167                 // der FlyFrm wird ueberstimmt.
2168                 if( nRight > nFlyRight )
2169                     nRight = nFlyRight;
2170                 bStop = sal_True;
2171             }
2172 		}
2173 	}
2174     (rFly.*fnRect->fnSetRight)( nRight );
2175 }
2176 // <--
2177 
2178 /*************************************************************************
2179  *						SwTxtFly::CalcLeftMargin()
2180  *
2181  * pFly ist der FlyFrm, der uns gerade ueberlappt.
2182  * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird.
2183  * Der linke Rand ist der linke Rand der aktuellen PrintArea oder
2184  * er wird durch den vorigen FlyFrm, der in die Zeile ragt, bestimmt.
2185  *************************************************************************/
2186 // --> OD 2006-08-15 #i68520#
2187 void SwTxtFly::CalcLeftMargin( SwRect &rFly,
2188                                SwAnchoredObjList::size_type nFlyPos,
2189                                const SwRect &rLine ) const
2190 {
2191     ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
2192             "SwTxtFly::CalcLeftMargin with swapped frame" )
2193     SWRECTFN( pCurrFrm )
2194     // --> OD 2004-12-14 #118796# - correct determination of left of printing area
2195     SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
2196     // <--
2197     const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();
2198 
2199     if( nLeft > nFlyLeft )
2200 		nLeft = rFly.Left();
2201 
2202     SwRect aLine( rLine );
2203     (aLine.*fnRect->fnSetLeft)( nLeft );
2204 
2205 	// Es koennte aber sein, dass in die gleiche Zeile noch ein anderes
2206 	// Object hineinragt, welches _ueber_ uns liegt.
2207 	// Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden
2208 	// unsichtbar, das heisst, dass sie bei der Berechnung der Raender
2209 	// anderer Flys ebenfalls nicht auffallen.
2210 	// 3301: pNext->Frm().IsOver( rLine ) ist noetig
2211 
2212     // --> OD 2006-08-15 #i68520#
2213     SwAnchoredObjList::size_type nMyPos = nFlyPos;
2214     while( ++nFlyPos < mpAnchoredObjList->size() )
2215     // <--
2216 	{
2217         // --> OD 2006-08-15 #i68520#
2218         const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
2219         const SwRect aTmp( pNext->GetObjRectWithSpaces() );
2220         // <--
2221         if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
2222 			break;
2223 	}
2224 
2225 	while( nFlyPos )
2226 	{
2227 		if( --nFlyPos == nMyPos )
2228 			continue;
2229         // --> OD 2006-08-15 #i68520#
2230         const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
2231         if( pNext == mpCurrAnchoredObj )
2232             continue;
2233         SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
2234         if( SURROUND_THROUGHT == eSurroundForTextWrap )
2235             continue;
2236         // <--
2237 
2238 		const SwRect aTmp( SwContourCache::CalcBoundRect
2239                 ( pNext, aLine, pCurrFrm, nFlyLeft, sal_False ) );
2240 
2241         if( (aTmp.*fnRect->fnGetLeft)() < nFlyLeft && aTmp.IsOver( aLine ) )
2242 		{
2243             // --> OD 2004-12-14 #118796# - no '+1', because <..fnGetRight>
2244             // returns the correct value.
2245             SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
2246             if ( nLeft <= nTmpRight )
2247                 nLeft = nTmpRight;
2248             // <--
2249 
2250 			break;
2251 		}
2252 	}
2253     (rFly.*fnRect->fnSetLeft)( nLeft );
2254 }
2255 // <--
2256 
2257 /*************************************************************************
2258  *						SwTxtFly::FlyToRect()
2259  *
2260  * IN:	dokumentglobal	(rRect)
2261  * OUT: dokumentglobal	(return-Wert)
2262  * Liefert zu einem SwFlyFrm das von ihm in Anspruch genommene Rechteck
2263  * unter Beruecksichtigung der eingestellten Attribute fuer den Abstand
2264  * zum Text zurueck.
2265  *************************************************************************/
2266 // --> OD 2006-08-15 #i68520#
2267 SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
2268                             const SwRect &rLine ) const
2269 {
2270     SWRECTFN( pCurrFrm )
2271 
2272     const long nXPos = pCurrFrm->IsRightToLeft() ?
2273                        rLine.Right() :
2274                        (rLine.*fnRect->fnGetLeft)();
2275 
2276     SwRect aFly = mbIgnoreContour ?
2277                   pAnchoredObj->GetObjRectWithSpaces() :
2278                   SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
2279                                                  nXPos, ! pCurrFrm->IsRightToLeft() );
2280 
2281     if( !aFly.Width() )
2282 		return aFly;
2283 
2284     SetNextTop( (aFly.*fnRect->fnGetBottom)() ); // Damit die Zeile ggf. bis zur Unterkante
2285 								 // des Rahmens waechst.
2286     SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );
2287 
2288 	// Bei LEFT und RIGHT vergroessern wir das Rechteck.
2289 	// Hier gibt es einige Probleme, wenn mehrere Frames zu sehen sind.
2290 	// Zur Zeit wird nur der einfachste Fall angenommen:
2291 	// LEFT bedeutet, dass der Text links vom Frame fliessen soll,
2292 	// d.h. der Frame blaeht sich bis zum rechten Rand der Printarea
2293 	// oder bis zum naechsten Frame auf.
2294 	// Bei RIGHT ist es umgekehrt.
2295 	// Ansonsten wird immer der eingestellte Abstand zwischen Text
2296 	// und Frame aufaddiert.
2297     switch( _GetSurroundForTextWrap( pAnchoredObj ) )
2298 	{
2299 		case SURROUND_LEFT :
2300 		{
2301 			CalcRightMargin( aFly, nFlyPos, rLine );
2302 			break;
2303 		}
2304 		case SURROUND_RIGHT :
2305 		{
2306 			CalcLeftMargin( aFly, nFlyPos, rLine );
2307 			break;
2308 		}
2309 		case SURROUND_NONE :
2310 		{
2311 			CalcRightMargin( aFly, nFlyPos, rLine );
2312 			CalcLeftMargin( aFly, nFlyPos, rLine );
2313 			break;
2314 		}
2315         default:
2316             break;
2317 	}
2318 	return aFly;
2319 }
2320 
2321 // --> OD 2006-08-15 #i68520#
2322 // new method <_GetSurroundForTextWrap(..)> replaces methods
2323 // <CalcSmart(..)> and <GetOrder(..)>
2324 /*************************************************************************
2325  *						SwTxtFly::CalcSmart()
2326  *
2327  * CalcSmart() liefert die Umlaufform zurueck.
2328  *
2329  * Auf beiden Seiten ist weniger als 2 cm Platz fuer den Text
2330  * 	 => kein Umlauf ( SURROUND_NONE )
2331  * Auf genau einer Seite ist mehr als 2 cm Platz
2332  *   => Umlauf auf dieser Seite ( SURROUND_LEFT / SURROUND_RIGHT )
2333  * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist breiter als 1,5 cm
2334  * 	 => Umlauf auf der breiteren Seite ( SURROUND_LEFT / SURROUND_RIGHT )
2335  * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist schmaler als 1,5 cm
2336  * 	 => beidseitiger Umlauf ( SURROUND_PARALLEL	)
2337  *
2338  *************************************************************************/
2339 
2340 // Umfluss nur auf Seiten mit mindestens 2 cm Platz fuer den Text
2341 #define TEXT_MIN 1134
2342 // Beidseitiger Umfluss bis zu einer Rahmenbreite von maximal 1,5 cm
2343 #define FRAME_MAX 850
2344 
2345 SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
2346 {
2347     const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
2348     const SwFmtSurround &rFlyFmt = pFmt->GetSurround();
2349     SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround();
2350 
2351     if( rFlyFmt.IsAnchorOnly() && pAnchoredObj->GetAnchorFrm() != GetMaster() )
2352     {
2353         const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
2354         if ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
2355             (FLY_AT_CHAR == rAnchor.GetAnchorId()))
2356         {
2357             return SURROUND_NONE;
2358         }
2359     }
2360 
2361     // Beim Durchlauf und Nowrap wird smart ignoriert.
2362     if( SURROUND_THROUGHT == eSurroundForTextWrap ||
2363         SURROUND_NONE == eSurroundForTextWrap )
2364         return eSurroundForTextWrap;
2365 
2366     // left is left and right is right
2367     if ( pCurrFrm->IsRightToLeft() )
2368     {
2369         if ( SURROUND_LEFT == eSurroundForTextWrap )
2370             eSurroundForTextWrap = SURROUND_RIGHT;
2371         else if ( SURROUND_RIGHT == eSurroundForTextWrap )
2372             eSurroundForTextWrap = SURROUND_LEFT;
2373     }
2374 
2375     // "idealer Seitenumlauf":
2376     if ( SURROUND_IDEAL == eSurroundForTextWrap )
2377     {
2378         SWRECTFN( pCurrFrm )
2379         const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
2380         const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
2381         const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
2382         long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
2383         long nFlyRight = (aRect.*fnRect->fnGetRight)();
2384 
2385         if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
2386             eSurroundForTextWrap = SURROUND_PARALLEL;
2387         else
2388         {
2389             long nLeft = nFlyLeft - nCurrLeft;
2390             long nRight = nCurrRight - nFlyRight;
2391             if( nFlyRight - nFlyLeft > FRAME_MAX )
2392             {
2393                 if( nLeft < nRight )
2394                     nLeft = 0;
2395                 else
2396                     nRight = 0;
2397             }
2398             if( nLeft < TEXT_MIN )
2399                 nLeft = 0;
2400             if( nRight < TEXT_MIN )
2401                 nRight = 0;
2402             if( nLeft )
2403                 eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
2404             else
2405                 eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
2406         }
2407     }
2408 
2409     return eSurroundForTextWrap;
2410 }
2411 
2412 /*************************************************************************
2413  *						SwTxtFly::IsAnyFrm( SwRect )
2414  *
2415  * IN: dokumentglobal
2416  *
2417  * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax)
2418  *
2419  *************************************************************************/
2420 
2421 sal_Bool SwTxtFly::IsAnyFrm( const SwRect &rLine ) const
2422 {
2423 
2424     SWAP_IF_SWAPPED( pCurrFrm )
2425 
2426 	ASSERT( bOn, "IsAnyFrm: Why?" );
2427 
2428     const sal_Bool bRet = ForEach( rLine, NULL, sal_False );
2429     UNDO_SWAP( pCurrFrm )
2430     return bRet;
2431 }
2432