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