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 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 146 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 278 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 337 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 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 648 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 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 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 814 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 843 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 866 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 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 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 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 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 postioning. 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 1365 AnchoredObjOrder( const sal_Bool bR2L, 1366 SwRectFn fnRect ) 1367 : mbR2L( bR2L ), 1368 mfnRect( fnRect ) 1369 {} 1370 1371 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# 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 1623 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 1664 SwContourCache::SwContourCache() : 1665 nPntCnt( 0 ), nObjCnt( 0 ) 1666 { 1667 memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) ); 1668 memset( pTextRanger, 0, sizeof(pTextRanger) ); 1669 } 1670 1671 SwContourCache::~SwContourCache() 1672 { 1673 for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] ) 1674 ; 1675 } 1676 1677 void SwContourCache::ClrObject( MSHORT nPos ) 1678 { 1679 ASSERT( pTextRanger[ nPos ], "ClrObject: Allready 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 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 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# 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 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 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 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 1966 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# 2065 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# 2084 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# 2189 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# 2269 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 2347 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 2423 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