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