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