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