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 pOut->DrawRect( aRegion[i].SVRect() ); 1118 else 1119 { 1120 ASSERT( ((SvxBrushItem*)-1) != rInf.GetBrushItem(), 1121 "DrawRect: Uninitialized BrushItem!" ); 1122 ::DrawGraphic( rInf.GetBrushItem(), pOut, rInf.GetBrushRect(), 1123 aRegion[i] ); 1124 } 1125 } 1126 } 1127 1128 // --> OD 2004-10-06 #i26945# - change first parameter: 1129 // Now it's the <SwAnchoredObject> instance of the floating screen object 1130 sal_Bool SwTxtFly::GetTop( const SwAnchoredObject* _pAnchoredObj, 1131 const sal_Bool bInFtn, 1132 const sal_Bool bInFooterOrHeader ) 1133 // <-- 1134 { 1135 // --> OD 2006-08-15 #i68520# 1136 // <mpCurrAnchoredObj> is set, if <pCurrFrm> is inside a fly frame 1137 if( _pAnchoredObj != mpCurrAnchoredObj ) 1138 // <-- 1139 { 1140 // --> OD 2004-10-06 #i26945# 1141 const SdrObject* pNew = _pAnchoredObj->GetDrawObj(); 1142 // <-- 1143 // #102344# Ignore connectors which have one or more connections 1144 if(pNew && pNew->ISA(SdrEdgeObj)) 1145 { 1146 if(((SdrEdgeObj*)pNew)->GetConnectedNode(sal_True) 1147 || ((SdrEdgeObj*)pNew)->GetConnectedNode(sal_False)) 1148 { 1149 return sal_False; 1150 } 1151 } 1152 1153 if( ( bInFtn || bInFooterOrHeader ) && bTopRule ) 1154 { 1155 // --> OD 2004-10-06 #i26945# 1156 const SwFrmFmt& rFrmFmt = _pAnchoredObj->GetFrmFmt(); 1157 const SwFmtAnchor& rNewA = rFrmFmt.GetAnchor(); 1158 // <-- 1159 if (FLY_AT_PAGE == rNewA.GetAnchorId()) 1160 { 1161 if ( bInFtn ) 1162 return sal_False; 1163 1164 if ( bInFooterOrHeader ) 1165 { 1166 SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() ); 1167 sal_Bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA || 1168 aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA; 1169 if( bVertPrt ) 1170 return sal_False; 1171 } 1172 } 1173 } 1174 1175 // --> OD 2006-08-15 #i68520# 1176 // bEvade: consider pNew, if we are not inside a fly 1177 // consider pNew, if pNew is lower of <mpCurrAnchoredObj> 1178 sal_Bool bEvade = !mpCurrAnchoredObj || 1179 Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew); 1180 1181 if ( !bEvade ) 1182 { 1183 // We are currently inside a fly frame and pNew is not 1184 // inside this fly frame. We can do some more checks if 1185 // we have to consider pNew. 1186 1187 // If bTopRule is not set, we ignore the frame types. 1188 // We directly check the z-order 1189 if ( !bTopRule ) 1190 bEvade = sal_True; 1191 else 1192 { 1193 // innerhalb von verketteten Flys wird nur Lowern ausgewichen 1194 // --> OD 2006-08-15 #i68520# 1195 const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain(); 1196 // <-- 1197 if ( !rChain.GetPrev() && !rChain.GetNext() ) 1198 { 1199 // --> OD 2004-10-06 #i26945# 1200 const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor(); 1201 // <-- 1202 // --> OD 2006-08-15 #i68520# 1203 const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor(); 1204 // <-- 1205 1206 // If <mpCurrAnchoredObj> is anchored as character, its content 1207 // does not wrap around pNew 1208 if (FLY_AS_CHAR == rCurrA.GetAnchorId()) 1209 return sal_False; 1210 1211 // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored 1212 // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew 1213 // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do 1214 // some more checks 1215 if (FLY_AT_PAGE == rNewA.GetAnchorId()) 1216 { 1217 if (FLY_AT_PAGE == rCurrA.GetAnchorId()) 1218 { 1219 bEvade = sal_True; 1220 } 1221 else 1222 return sal_False; 1223 } 1224 else if (FLY_AT_PAGE == rCurrA.GetAnchorId()) 1225 return sal_False; // Seitengebundene weichen nur seitengeb. aus 1226 else if (FLY_AT_FLY == rNewA.GetAnchorId()) 1227 bEvade = sal_True; // Nicht seitengeb. weichen Rahmengeb. aus 1228 else if( FLY_AT_FLY == rCurrA.GetAnchorId() ) 1229 return sal_False; // Rahmengebundene weichen abs.geb. nicht aus 1230 // --> OD 2006-01-30 #i57062# 1231 // In order to avoid loop situation, it's decided to adjust 1232 // the wrapping behaviour of content of at-paragraph/at-character 1233 // anchored objects to one in the page header/footer and 1234 // the document body --> content of at-paragraph/at-character 1235 // anchored objects doesn't wrap around each other. 1236 // else if( bInFooterOrHeader ) 1237 // return sal_False; // In header or footer no wrapping 1238 // // if both bounded at paragraph 1239 // else // Zwei Flies mit (auto-)absatzgebunder Verankerung ... 1240 // // ... entscheiden nach der Reihenfolge ihrer Anker im Dok. 1241 // bEvade = rNewA.GetCntntAnchor()->nNode.GetIndex() <= 1242 // rCurrA.GetCntntAnchor()->nNode.GetIndex(); 1243 else 1244 return sal_False; 1245 // <-- 1246 } 1247 } 1248 1249 // aber: es wird niemals einem hierarchisch untergeordnetem 1250 // ausgewichen und ausserdem braucht nur bei Ueberlappung 1251 // ausgewichen werden. 1252 // --> OD 2006-08-15 #i68520# 1253 bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() ); 1254 // <-- 1255 if( bEvade ) 1256 { 1257 // --> OD 2006-08-15 #i68520# 1258 SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() ); 1259 if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) ) 1260 bEvade = sal_False; 1261 // <-- 1262 } 1263 } 1264 1265 if ( bEvade ) 1266 { 1267 // --> OD 2004-10-06 #i26945# 1268 const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor(); 1269 // <-- 1270 ASSERT( FLY_AS_CHAR != rNewA.GetAnchorId(), 1271 "Don't call GetTop with a FlyInCntFrm" ); 1272 if (FLY_AT_PAGE == rNewA.GetAnchorId()) 1273 return sal_True; // Seitengebundenen wird immer ausgewichen. 1274 1275 // Wenn absatzgebundene Flys in einem FlyCnt gefangen sind, so 1276 // endet deren Einflussbereich an den Grenzen des FlyCnt! 1277 // Wenn wir aber gerade den Text des FlyCnt formatieren, dann 1278 // muss er natuerlich dem absatzgebundenen Frm ausweichen! 1279 // pCurrFrm ist der Anker von pNew? 1280 // --> OD 2004-10-06 #i26945# 1281 const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm(); 1282 // <-- 1283 if( pTmp == pCurrFrm ) 1284 return sal_True; 1285 if( pTmp->IsTxtFrm() && ( pTmp->IsInFly() || pTmp->IsInFtn() ) ) 1286 { 1287 // --> OD 2004-10-06 #i26945# 1288 Point aPos = _pAnchoredObj->GetObjRect().Pos(); 1289 // <-- 1290 pTmp = GetVirtualUpper( pTmp, aPos ); 1291 } 1292 // --> OD 2004-10-06 #i26945# 1293 // --> OD 2004-11-29 #115759# 1294 // If <pTmp> is a text frame inside a table, take the upper 1295 // of the anchor frame, which contains the anchor position. 1296 else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() ) 1297 { 1298 pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj) 1299 ->GetAnchorFrmContainingAnchPos()->GetUpper(); 1300 } 1301 // <-- 1302 // --> OD 2004-05-13 #i28701# - consider all objects in same context, 1303 // if wrapping style is considered on object positioning. 1304 // Thus, text will wrap around negative positioned objects. 1305 // --> OD 2004-08-25 #i3317# - remove condition on checking, 1306 // if wrappings style is considered on object postioning. 1307 // Thus, text is wrapping around negative positioned objects. 1308 // --> OD 2004-10-20 #i35640# - no consideration of negative 1309 // positioned objects, if wrapping style isn't considered on 1310 // object position and former text wrapping is applied. 1311 // This condition is typically for documents imported from the 1312 // OpenOffice.org file format. 1313 const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess(); 1314 if ( ( pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) || 1315 !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) && 1316 ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) ) 1317 { 1318 return sal_True; 1319 } 1320 // <-- 1321 1322 const SwFrm* pHeader = 0; 1323 if ( pCurrFrm->GetNext() != pTmp && 1324 ( IsFrmInSameKontext( pTmp, pCurrFrm ) || 1325 // --> #i13832#, #i24135# wrap around objects in page header 1326 ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) && 1327 0 != ( pHeader = pTmp->FindFooterOrHeader() ) && 1328 !pHeader->IsFooterFrm() && 1329 pCurrFrm->IsInDocBody() ) ) ) 1330 // <-- 1331 { 1332 if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() ) 1333 return sal_True; 1334 1335 // Compare indices: 1336 // Den Index des anderen erhalten wir immer ueber das Ankerattr. 1337 sal_uLong nTmpIndex = rNewA.GetCntntAnchor()->nNode.GetIndex(); 1338 // Jetzt wird noch ueberprueft, ob der aktuelle Absatz vor dem 1339 // Anker des verdraengenden Objekts im Text steht, dann wird 1340 // nicht ausgewichen. 1341 // Der Index wird moeglichst ueber einen SwFmtAnchor ermittelt, 1342 // da sonst recht teuer. 1343 if( ULONG_MAX == nIndex ) 1344 nIndex = pCurrFrm->GetNode()->GetIndex(); 1345 1346 if( nIndex >= nTmpIndex ) 1347 return sal_True; 1348 } 1349 } 1350 } 1351 return sal_False; 1352 } 1353 // --> OD 2006-08-15 #i68520# 1354 struct AnchoredObjOrder 1355 { 1356 sal_Bool mbR2L; 1357 SwRectFn mfnRect; 1358 1359 AnchoredObjOrder( const sal_Bool bR2L, 1360 SwRectFn fnRect ) 1361 : mbR2L( bR2L ), 1362 mfnRect( fnRect ) 1363 {} 1364 1365 bool operator()( const SwAnchoredObject* pListedAnchoredObj, 1366 const SwAnchoredObject* pNewAnchoredObj ) 1367 { 1368 const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() ); 1369 const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() ); 1370 if ( ( mbR2L && 1371 ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() == 1372 (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) || 1373 ( !mbR2L && 1374 ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() == 1375 (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) ) 1376 { 1377 SwTwips nTopDiff = 1378 (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(), 1379 (aBoundRectOfListedObj.*mfnRect->fnGetTop)() ); 1380 if ( nTopDiff == 0 && 1381 ( ( mbR2L && 1382 ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() > 1383 (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) || 1384 ( !mbR2L && 1385 ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() < 1386 (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) ) 1387 { 1388 return true; 1389 } 1390 else if ( nTopDiff > 0 ) 1391 { 1392 return true; 1393 } 1394 } 1395 else if ( ( mbR2L && 1396 ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() > 1397 (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) || 1398 ( !mbR2L && 1399 ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() < 1400 (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) ) 1401 { 1402 return true; 1403 } 1404 1405 return false; 1406 } 1407 }; 1408 1409 // --> OD 2006-08-15 #i68520# 1410 SwAnchoredObjList* SwTxtFly::InitAnchoredObjList() 1411 { 1412 ASSERT( pCurrFrm, "InitFlyList: No Frame, no FlyList" ); 1413 // --> OD 2006-08-15 #i68520# 1414 ASSERT( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" ); 1415 // <-- 1416 1417 SWAP_IF_SWAPPED( pCurrFrm ) 1418 1419 const SwSortedObjs *pSorted = pPage->GetSortedObjs(); 1420 const sal_uInt32 nCount = pSorted ? pSorted->Count() : 0; 1421 // --> #108724# Page header/footer content doesn't have to wrap around 1422 // floating screen objects 1423 const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader(); 1424 const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess(); 1425 // --> OD 2005-01-12 #i40155# - check, if frame is marked not to wrap 1426 const sal_Bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) || 1427 ( !pCurrFrm->IsInFtn() && !bFooterHeader ) ) && 1428 !SwLayouter::FrmNotToWrap( *pCurrFrm->GetTxtNode()->getIDocumentLayoutAccess(), *pCurrFrm ); 1429 // <-- 1430 1431 bOn = sal_False; 1432 1433 if( nCount && bWrapAllowed ) 1434 { 1435 // --> OD 2006-08-15 #i68520# 1436 mpAnchoredObjList = new SwAnchoredObjList(); 1437 // <-- 1438 1439 // --> OD 2004-06-18 #i28701# - consider complete frame area for new 1440 // text wrapping 1441 SwRect aRect; 1442 if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) 1443 { 1444 aRect = pCurrFrm->Prt(); 1445 aRect += pCurrFrm->Frm().Pos(); 1446 } 1447 else 1448 { 1449 aRect = pCurrFrm->Frm(); 1450 } 1451 // Wir machen uns etwas kleiner als wir sind, 1452 // damit Ein-Twip-Ueberlappungen ignoriert werden. (#49532) 1453 SWRECTFN( pCurrFrm ) 1454 const long nRight = (aRect.*fnRect->fnGetRight)() - 1; 1455 const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1; 1456 const sal_Bool bR2L = pCurrFrm->IsRightToLeft(); 1457 1458 const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess(); 1459 1460 for( sal_uInt32 i = 0; i < nCount; i++ ) 1461 { 1462 // --> OD 2006-08-15 #i68520# 1463 // SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ]; 1464 // const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() ); 1465 1466 // // OD 2004-01-15 #110582# - do not consider hidden objects 1467 // // OD 2004-05-13 #i28701# - check, if object has to be considered 1468 // // for text wrap. 1469 // if ( !pDoc->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) || 1470 // !pAnchoredObj->ConsiderForTextWrap() || 1471 // nRight < (aBound.*fnRect->fnGetLeft)() || 1472 // (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(), 1473 // (aBound.*fnRect->fnGetBottom)() ) > 0 || 1474 // nLeft > (aBound.*fnRect->fnGetRight)() || 1475 // // --> OD 2004-12-17 #118809# - If requested, do not consider 1476 // // objects in page header|footer for text frames not in page 1477 // // header|footer. This is requested for the calculation of 1478 // // the base offset for objects <SwTxtFrm::CalcBaseOfstForFly()> 1479 // ( mbIgnoreObjsInHeaderFooter && !bFooterHeader && 1480 // pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) || 1481 // // <-- 1482 // // --> FME 2004-07-14 #i20505# Do not consider oversized objects 1483 // (aBound.*fnRect->fnGetHeight)() > 1484 // 2 * (pPage->Frm().*fnRect->fnGetHeight)() ) 1485 // // <-- 1486 // { 1487 // continue; 1488 // } 1489 SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ]; 1490 if ( !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) || 1491 !pAnchoredObj->ConsiderForTextWrap() || 1492 ( mbIgnoreObjsInHeaderFooter && !bFooterHeader && 1493 pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) ) 1494 { 1495 continue; 1496 } 1497 1498 const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() ); 1499 if ( nRight < (aBound.*fnRect->fnGetLeft)() || 1500 (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(), 1501 (aBound.*fnRect->fnGetBottom)() ) > 0 || 1502 nLeft > (aBound.*fnRect->fnGetRight)() || 1503 (aBound.*fnRect->fnGetHeight)() > 1504 2 * (pPage->Frm().*fnRect->fnGetHeight)() ) 1505 { 1506 continue; 1507 } 1508 // <-- 1509 1510 // --> OD 2004-10-06 #i26945# - pass <pAnchoredObj> to method 1511 // <GetTop(..)> instead of only the <SdrObject> instance of the 1512 // anchored object 1513 if ( GetTop( pAnchoredObj, pCurrFrm->IsInFtn(), bFooterHeader ) ) 1514 // <-- 1515 { 1516 // OD 11.03.2003 #107862# - adjust insert position: 1517 // overlapping objects should be sorted from left to right and 1518 // inside left to right sorting from top to bottom. 1519 // If objects on the same position are found, they are sorted 1520 // on its width. 1521 // --> OD 2006-08-15 #i68520# 1522 // sal_uInt16 nPos = pFlyList->Count(); 1523 // while ( nPos ) 1524 // { 1525 // SdrObject* pTmpObj = (*pFlyList)[ --nPos ]; 1526 // const SwRect aBoundRectOfTmpObj( GetBoundRect( pTmpObj ) ); 1527 // if ( ( bR2L && 1528 // ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() == 1529 // (aBound.*fnRect->fnGetRight)() ) ) || 1530 // ( !bR2L && 1531 // ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() == 1532 // (aBound.*fnRect->fnGetLeft)() ) ) ) 1533 // { 1534 // SwTwips nTopDiff = 1535 // (*fnRect->fnYDiff)( (aBound.*fnRect->fnGetTop)(), 1536 // (aBoundRectOfTmpObj.*fnRect->fnGetTop)() ); 1537 // if ( nTopDiff == 0 && 1538 // ( ( bR2L && 1539 // ( (aBound.*fnRect->fnGetLeft)() > 1540 // (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ) ) || 1541 // ( !bR2L && 1542 // ( (aBound.*fnRect->fnGetRight)() < 1543 // (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ) ) ) ) 1544 // { 1545 // ++nPos; 1546 // break; 1547 // } 1548 // else if ( nTopDiff > 0 ) 1549 // { 1550 // ++nPos; 1551 // break; 1552 // } 1553 // } 1554 // else if ( ( bR2L && 1555 // ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() > 1556 // (aBound.*fnRect->fnGetRight)() ) ) || 1557 // ( !bR2L && 1558 // ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() < 1559 // (aBound.*fnRect->fnGetLeft)() ) ) ) 1560 // { 1561 // ++nPos; 1562 // break; 1563 // } 1564 // } 1565 // SdrObject* pSdrObj = pAnchoredObj->DrawObj(); 1566 // pFlyList->C40_INSERT( SdrObject, pSdrObj, nPos ); 1567 { 1568 SwAnchoredObjList::iterator aInsPosIter = 1569 std::lower_bound( mpAnchoredObjList->begin(), 1570 mpAnchoredObjList->end(), 1571 pAnchoredObj, 1572 AnchoredObjOrder( bR2L, fnRect ) ); 1573 1574 mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj ); 1575 } 1576 // <-- 1577 1578 const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround(); 1579 // --> OD 2006-08-15 #i68520# 1580 if ( rFlyFmt.IsAnchorOnly() && 1581 pAnchoredObj->GetAnchorFrm() == GetMaster() ) 1582 // <-- 1583 { 1584 const SwFmtVertOrient &rTmpFmt = 1585 pAnchoredObj->GetFrmFmt().GetVertOrient(); 1586 if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() ) 1587 nMinBottom = ( bVert && nMinBottom ) ? 1588 Min( nMinBottom, aBound.Left() ) : 1589 Max( nMinBottom, (aBound.*fnRect->fnGetBottom)() ); 1590 } 1591 1592 bOn = sal_True; 1593 } 1594 } 1595 if( nMinBottom ) 1596 { 1597 SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)(); 1598 if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 ) 1599 nMinBottom = nMax; 1600 } 1601 } 1602 else 1603 { 1604 // --> OD 2006-08-15 #i68520# 1605 mpAnchoredObjList = new SwAnchoredObjList(); 1606 // <-- 1607 } 1608 1609 UNDO_SWAP( pCurrFrm ) 1610 1611 // --> OD 2006-08-15 #i68520# 1612 return mpAnchoredObjList; 1613 // <-- 1614 } 1615 // <-- 1616 1617 SwTwips SwTxtFly::CalcMinBottom() const 1618 { 1619 SwTwips nRet = 0; 1620 const SwSortedObjs *pDrawObj = GetMaster()->GetDrawObjs(); 1621 const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0; 1622 if( nCount ) 1623 { 1624 SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom(); 1625 for( sal_uInt32 i = 0; i < nCount; i++ ) 1626 { 1627 SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ]; 1628 const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround(); 1629 if( rFlyFmt.IsAnchorOnly() ) 1630 { 1631 const SwFmtVertOrient &rTmpFmt = 1632 pAnchoredObj->GetFrmFmt().GetVertOrient(); 1633 if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() ) 1634 { 1635 const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() ); 1636 if( aBound.Top() < nEndOfFrm ) 1637 nRet = Max( nRet, aBound.Bottom() ); 1638 } 1639 } 1640 } 1641 SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() + 1642 pCurrFrm->GetUpper()->Prt().Bottom(); 1643 if( nRet > nMax ) 1644 nRet = nMax; 1645 } 1646 return nRet; 1647 } 1648 1649 /************************************************************************* 1650 * Hier erfolgt die Berechnung der Kontur ... 1651 * CalcBoundRect(..) und andere 1652 *************************************************************************/ 1653 1654 /************************************************************************* 1655 * class SwContourCache 1656 *************************************************************************/ 1657 1658 SwContourCache::SwContourCache() : 1659 nPntCnt( 0 ), nObjCnt( 0 ) 1660 { 1661 memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) ); 1662 memset( pTextRanger, 0, sizeof(pTextRanger) ); 1663 } 1664 1665 SwContourCache::~SwContourCache() 1666 { 1667 for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] ) 1668 ; 1669 } 1670 1671 void SwContourCache::ClrObject( MSHORT nPos ) 1672 { 1673 ASSERT( pTextRanger[ nPos ], "ClrObject: Allready cleared. Good Bye!" ); 1674 nPntCnt -= pTextRanger[ nPos ]->GetPointCount(); 1675 delete pTextRanger[ nPos ]; 1676 --nObjCnt; 1677 memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1, 1678 ( nObjCnt - nPos ) * sizeof( SdrObject* ) ); 1679 memmove( pTextRanger + nPos, pTextRanger + nPos + 1, 1680 ( nObjCnt - nPos ) * sizeof( TextRanger* ) ); 1681 } 1682 1683 void ClrContourCache( const SdrObject *pObj ) 1684 { 1685 if( pContourCache && pObj ) 1686 for( MSHORT i = 0; i < pContourCache->GetCount(); ++i ) 1687 if( pObj == pContourCache->GetObject( i ) ) 1688 { 1689 pContourCache->ClrObject( i ); 1690 break; 1691 } 1692 } 1693 1694 void ClrContourCache() 1695 { 1696 if( pContourCache ) 1697 { 1698 for( MSHORT i = 0; i < pContourCache->GetCount(); 1699 delete pContourCache->pTextRanger[ i++ ] ) 1700 ; 1701 pContourCache->nObjCnt = 0; 1702 pContourCache->nPntCnt = 0; 1703 } 1704 } 1705 1706 /************************************************************************* 1707 * SwContourCache::CalcBoundRect 1708 * berechnet das Rechteck, welches vom Objekt in der angegebenen Zeile 1709 * ueberdeckt wird. 1710 * Bei _nicht_ konturumflossenen Objekten ist dies einfach die Ueber- 1711 * lappung von BoundRect (inkl. Abstand!) und Zeile, 1712 * bei Konturumfluss wird das Polypolygon des Objekts abgeklappert 1713 *************************************************************************/ 1714 // --> OD 2006-08-15 #i68520# 1715 const SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj, 1716 const SwRect &rLine, 1717 const SwTxtFrm* pFrm, 1718 const long nXPos, 1719 const sal_Bool bRight ) 1720 { 1721 SwRect aRet; 1722 const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt()); 1723 if( pFmt->GetSurround().IsContour() && 1724 ( !pAnchoredObj->ISA(SwFlyFrm) || 1725 ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() && 1726 static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) ) 1727 { 1728 aRet = pAnchoredObj->GetObjRectWithSpaces(); 1729 if( aRet.IsOver( rLine ) ) 1730 { 1731 if( !pContourCache ) 1732 pContourCache = new SwContourCache; 1733 1734 aRet = pContourCache->ContourRect( 1735 pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight ); 1736 } 1737 else 1738 aRet.Width( 0 ); 1739 } 1740 else 1741 { 1742 aRet = pAnchoredObj->GetObjRectWithSpaces(); 1743 } 1744 1745 return aRet; 1746 } 1747 // <-- 1748 1749 const SwRect SwContourCache::ContourRect( const SwFmt* pFmt, 1750 const SdrObject* pObj, const SwTxtFrm* pFrm, const SwRect &rLine, 1751 const long nXPos, const sal_Bool bRight ) 1752 { 1753 SwRect aRet; 1754 MSHORT nPos = 0; // Suche im Cache ... 1755 while( nPos < GetCount() && pObj != pSdrObj[ nPos ] ) 1756 ++nPos; 1757 if( GetCount() == nPos ) // nicht gefunden 1758 { 1759 if( nObjCnt == POLY_CNT ) 1760 { 1761 nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount(); 1762 delete pTextRanger[ nObjCnt ]; 1763 } 1764 ::basegfx::B2DPolyPolygon aPolyPolygon; 1765 ::basegfx::B2DPolyPolygon* pPolyPolygon = 0L; 1766 1767 if ( pObj->ISA(SwVirtFlyDrawObj) ) 1768 { 1769 // Vorsicht #37347: Das GetContour() fuehrt zum Laden der Grafik, 1770 // diese aendert dadurch ggf. ihre Groesse, ruft deshalb ein 1771 // ClrObject() auf. 1772 PolyPolygon aPoly; 1773 if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) ) 1774 aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)-> 1775 GetFlyFrm()->Frm().SVRect() ); 1776 aPolyPolygon.clear(); 1777 aPolyPolygon.append(aPoly.getB2DPolyPolygon()); 1778 } 1779 else 1780 { 1781 if( !pObj->ISA( E3dObject ) ) 1782 { 1783 aPolyPolygon = pObj->TakeXorPoly(); 1784 } 1785 1786 ::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour()); 1787 pPolyPolygon = new ::basegfx::B2DPolyPolygon(aContourPoly); 1788 } 1789 const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace(); 1790 const SvxULSpaceItem &rULSpace = pFmt->GetULSpace(); 1791 memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) ); 1792 memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) ); 1793 pSdrObj[ 0 ] = pObj; // Wg. #37347 darf das Object erst nach dem 1794 // GetContour() eingetragen werden. 1795 pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20, 1796 (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(), 1797 pFmt->GetSurround().IsOutside(), sal_False, pFrm->IsVertical() ); 1798 pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() ); 1799 pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() ); 1800 1801 delete pPolyPolygon; 1802 // UPPER_LOWER_TEST 1803 #ifdef DBG_UTIL 1804 const ViewShell* pTmpViewShell = pFmt->GetDoc()->GetCurrentViewShell(); 1805 if( pTmpViewShell ) 1806 { 1807 sal_Bool bT2 = pTmpViewShell->GetViewOptions()->IsTest2(); 1808 sal_Bool bT6 = pTmpViewShell->GetViewOptions()->IsTest6(); 1809 if( bT2 || bT6 ) 1810 { 1811 if( bT2 ) 1812 pTextRanger[ 0 ]->SetFlag7( sal_True ); 1813 else 1814 pTextRanger[ 0 ]->SetFlag6( sal_True ); 1815 } 1816 } 1817 #endif 1818 nPntCnt += pTextRanger[ 0 ]->GetPointCount(); 1819 while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN ) 1820 { 1821 nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount(); 1822 delete pTextRanger[ nObjCnt ]; 1823 } 1824 } 1825 else if( nPos ) 1826 { 1827 const SdrObject* pTmpObj = pSdrObj[ nPos ]; 1828 TextRanger* pTmpRanger = pTextRanger[ nPos ]; 1829 memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nPos * sizeof( SdrObject* ) ); 1830 memmove( pTextRanger + 1, pTextRanger, nPos * sizeof( TextRanger* ) ); 1831 pSdrObj[ 0 ] = pTmpObj; 1832 pTextRanger[ 0 ] = pTmpRanger; 1833 } 1834 SWRECTFN( pFrm ) 1835 long nTmpTop = (rLine.*fnRect->fnGetTop)(); 1836 // fnGetBottom is top + height 1837 long nTmpBottom = (rLine.*fnRect->fnGetBottom)(); 1838 1839 Range aRange( Min( nTmpTop, nTmpBottom ), Max( nTmpTop, nTmpBottom ) ); 1840 1841 SvLongs *pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange ); 1842 1843 MSHORT nCount; 1844 if( 0 != ( nCount = pTmp->Count() ) ) 1845 { 1846 MSHORT nIdx = 0; 1847 while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos ) 1848 ++nIdx; 1849 sal_Bool bOdd = nIdx % 2 ? sal_True : sal_False; 1850 sal_Bool bSet = sal_True; 1851 if( bOdd ) 1852 --nIdx; // innerhalb eines Intervalls 1853 else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) ) 1854 { 1855 if( nIdx ) 1856 nIdx -= 2; // ein Intervall nach links gehen 1857 else 1858 bSet = sal_False; // vor dem erstem Intervall 1859 } 1860 1861 if( bSet && nIdx < nCount ) 1862 { 1863 (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(), 1864 (rLine.*fnRect->fnGetHeight)() ); 1865 (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] ); 1866 (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 ); 1867 } 1868 } 1869 return aRet; 1870 } 1871 1872 /************************************************************************* 1873 * SwContourCache::ShowContour() 1874 * zeichnet die PolyPolygone des Caches zu Debugzwecken. 1875 *************************************************************************/ 1876 #ifdef DBG_UTIL 1877 1878 void SwContourCache::ShowContour( OutputDevice* pOut, const SdrObject* pObj, 1879 const Color& rClosedColor, const Color& rOpenColor ) 1880 { 1881 MSHORT nPos = 0; // Suche im Cache ... 1882 while( nPos < POLY_CNT && pObj != pSdrObj[ nPos ] ) 1883 ++nPos; 1884 if( POLY_CNT != nPos ) 1885 { 1886 const PolyPolygon* pPol = pTextRanger[ nPos ]->GetLinePolygon(); 1887 if( !pPol ) 1888 pPol = &(pTextRanger[ nPos ]->GetPolyPolygon()); 1889 for( MSHORT i = 0; i < pPol->Count(); ++i ) 1890 { 1891 pOut->SetLineColor( rOpenColor ); 1892 const Polygon& rPol = (*pPol)[ i ]; 1893 MSHORT nCount = rPol.GetSize(); 1894 if( nCount > 1 && rPol[ 0 ] == rPol[ nCount - 1 ] ) 1895 pOut->SetLineColor( rClosedColor ); 1896 pOut->DrawPolygon( rPol ); 1897 } 1898 #if OSL_DEBUG_LEVEL > 1 1899 static KSHORT nRadius = 0; 1900 if( nRadius ) 1901 { 1902 KSHORT nHalf = nRadius / 2; 1903 Size aSz( nRadius, nRadius ); 1904 for( MSHORT i = 0; i < pPol->Count(); ++i ) 1905 { 1906 const Polygon& rPol = (*pPol)[ i ]; 1907 MSHORT nCount = rPol.GetSize(); 1908 for( MSHORT k = 0; k < nCount; ++k ) 1909 { 1910 Point aPt( rPol[ k ] ); 1911 aPt.X() -= nHalf; 1912 aPt.Y() -= nHalf; 1913 Rectangle aTmp( aPt, aSz ); 1914 pOut->DrawEllipse( aTmp ); 1915 } 1916 } 1917 } 1918 #endif 1919 } 1920 } 1921 #endif 1922 1923 /************************************************************************* 1924 * SwTxtFly::ShowContour() 1925 * zeichnet die PolyPolygone des Caches zu Debugzwecken. 1926 *************************************************************************/ 1927 #ifdef DBG_UTIL 1928 1929 void SwTxtFly::ShowContour( OutputDevice* pOut ) 1930 { 1931 MSHORT nFlyCount; 1932 if( bOn && ( 0 != ( nFlyCount = static_cast<sal_uInt16>(GetAnchoredObjList()->size() ) ) ) ) 1933 { 1934 Color aRedColor( COL_LIGHTRED ); 1935 Color aGreenColor( COL_LIGHTGREEN ); 1936 Color aSaveColor( pOut->GetLineColor() ); 1937 for( MSHORT j = 0; j < nFlyCount; ++j ) 1938 { 1939 const SwAnchoredObject* pObj = (*mpAnchoredObjList)[ j ]; 1940 if( !pObj->GetFrmFmt().GetSurround().IsContour() ) 1941 { 1942 Rectangle aRect = pObj->GetObjRectWithSpaces().SVRect(); 1943 pOut->DrawRect( aRect ); 1944 continue; 1945 } 1946 pContourCache->ShowContour( pOut, pObj->GetDrawObj(), aRedColor, aGreenColor ); 1947 } 1948 pOut->SetLineColor( aSaveColor ); 1949 } 1950 } 1951 #endif 1952 1953 /************************************************************************* 1954 * SwTxtFly::ForEach() 1955 * 1956 * sucht nach dem ersten Objekt, welches mit dem Rechteck ueberlappt 1957 * 1958 *************************************************************************/ 1959 1960 sal_Bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, sal_Bool bAvoid ) const 1961 { 1962 SWAP_IF_SWAPPED( pCurrFrm ) 1963 1964 sal_Bool bRet = sal_False; 1965 // --> OD 2006-08-15 #i68520# 1966 SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 ); 1967 if ( bOn && nCount > 0 ) 1968 // <-- 1969 { 1970 for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i ) 1971 { 1972 // --> OD 2006-08-15 #i68520# 1973 const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i]; 1974 1975 SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() ); 1976 // <-- 1977 1978 // Optimierung 1979 SWRECTFN( pCurrFrm ) 1980 if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() ) 1981 break; 1982 // --> OD 2006-08-15 #i68520# 1983 if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) ) 1984 // <-- 1985 { 1986 // --> OD 2006-08-15 #i68520# 1987 const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) ); 1988 const SwFmtSurround &rSur = pFmt->GetSurround(); 1989 // <-- 1990 if( bAvoid ) 1991 { 1992 // Wenn der Text drunter durchlaeuft, bleibt die 1993 // Formatierung unbeeinflusst. Im LineIter::DrawText() 1994 // muessen "nur" geschickt die ClippingRegions gesetzt werden ... 1995 const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); 1996 if( ( SURROUND_THROUGHT == rSur.GetSurround() && 1997 ( !rSur.IsAnchorOnly() || 1998 // --> OD 2006-08-15 #i68520# 1999 GetMaster() == pAnchoredObj->GetAnchorFrm() || 2000 // <-- 2001 ((FLY_AT_PARA != rAnchor.GetAnchorId()) && 2002 (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) ) 2003 || aRect.Top() == WEIT_WECH ) 2004 continue; 2005 } 2006 2007 // --> OD 2006-01-20 #i58642# 2008 // Compare <GetMaster()> instead of <pCurrFrm> with the anchor 2009 // frame of the anchored object, because a follow frame have 2010 // to ignore the anchored objects of its master frame. 2011 // Note: Anchored objects are always registered at the master 2012 // frame, exception are as-character anchored objects, 2013 // but these aren't handled here. 2014 // --> OD 2006-08-15 #i68520# 2015 if ( mbIgnoreCurrentFrame && 2016 GetMaster() == pAnchoredObj->GetAnchorFrm() ) 2017 continue; 2018 // <-- 2019 2020 if( pRect ) 2021 { 2022 // --> OD 2006-08-15 #i68520# 2023 SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect ); 2024 // <-- 2025 if( aFly.IsEmpty() || !aFly.IsOver( rRect ) ) 2026 continue; 2027 if( !bRet || ( 2028 ( !pCurrFrm->IsRightToLeft() && 2029 ( (aFly.*fnRect->fnGetLeft)() < 2030 (pRect->*fnRect->fnGetLeft)() ) ) || 2031 ( pCurrFrm->IsRightToLeft() && 2032 ( (aFly.*fnRect->fnGetRight)() > 2033 (pRect->*fnRect->fnGetRight)() ) ) ) ) 2034 *pRect = aFly; 2035 if( rSur.IsContour() ) 2036 { 2037 bRet = sal_True; 2038 continue; 2039 } 2040 } 2041 bRet = sal_True; 2042 break; 2043 } 2044 } 2045 } 2046 2047 UNDO_SWAP( pCurrFrm ) 2048 2049 return bRet; 2050 } 2051 2052 /************************************************************************* 2053 * SwTxtFly::GetPos() 2054 * 2055 * liefert die Position im sorted Array zurueck 2056 *************************************************************************/ 2057 2058 // --> OD 2006-08-15 #i68520# 2059 SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const 2060 { 2061 SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size(); 2062 SwAnchoredObjList::size_type nRet = 0; 2063 while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] ) 2064 ++nRet; 2065 return nRet; 2066 } 2067 // <-- 2068 2069 /************************************************************************* 2070 * SwTxtFly::CalcRightMargin() 2071 * 2072 * pObj ist das Object, der uns gerade ueberlappt. 2073 * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird. 2074 * Der rechte Rand ist der rechte Rand oder 2075 * er wird durch das naechste Object, welches in die Zeile ragt, bestimmt. 2076 *************************************************************************/ 2077 // --> OD 2006-08-15 #i68520# 2078 void SwTxtFly::CalcRightMargin( SwRect &rFly, 2079 SwAnchoredObjList::size_type nFlyPos, 2080 const SwRect &rLine ) const 2081 { 2082 // Normalerweise ist der rechte Rand der rechte Rand der Printarea. 2083 ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(), 2084 "SwTxtFly::CalcRightMargin with swapped frame" ) 2085 SWRECTFN( pCurrFrm ) 2086 // --> OD 2004-12-14 #118796# - correct determination of right of printing area 2087 SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)(); 2088 // <-- 2089 SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)(); 2090 SwRect aLine( rLine ); 2091 (aLine.*fnRect->fnSetRight)( nRight ); 2092 (aLine.*fnRect->fnSetLeft)( (rFly.*fnRect->fnGetLeft)() ); 2093 2094 // Es koennte aber sein, dass in die gleiche Zeile noch ein anderes 2095 // Object hineinragt, welches _ueber_ uns liegt. 2096 // Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden 2097 // unsichtbar, das heisst, dass sie bei der Berechnung der Raender 2098 // anderer Flys ebenfalls nicht auffallen. 2099 // 3301: pNext->Frm().IsOver( rLine ) ist noetig 2100 // --> OD 2006-08-15 #i68520# 2101 SwSurround eSurroundForTextWrap; 2102 // <-- 2103 2104 sal_Bool bStop = sal_False; 2105 // --> OD 2006-08-15 #i68520# 2106 SwAnchoredObjList::size_type nPos = 0; 2107 // <-- 2108 2109 // --> OD 2006-08-15 #i68520# 2110 while( nPos < mpAnchoredObjList->size() && !bStop ) 2111 // <-- 2112 { 2113 if( nPos == nFlyPos ) 2114 { 2115 ++nPos; 2116 continue; 2117 } 2118 // --> OD 2006-08-15 #i68520# 2119 const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ]; 2120 if ( pNext == mpCurrAnchoredObj ) 2121 continue; 2122 eSurroundForTextWrap = _GetSurroundForTextWrap( pNext ); 2123 if( SURROUND_THROUGHT == eSurroundForTextWrap ) 2124 continue; 2125 // <-- 2126 2127 const SwRect aTmp( SwContourCache::CalcBoundRect 2128 ( pNext, aLine, pCurrFrm, nFlyRight, sal_True ) ); 2129 SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)(); 2130 2131 // Optimierung: 2132 // In nNextTop wird notiert, an welcher Y-Positon mit Aenderung der 2133 // Rahmenverhaeltnisse gerechnet werden muss. Dies dient dazu, dass, 2134 // obwohl nur die Rahmen in der aktuellen Zeilenhoehe betrachtet werden, 2135 // bei Rahmen ohne Umlauf die Zeilenhoehe so erhoeht wird, dass mit einer 2136 // einzigen Zeile die Unterkante das Rahmens oder ggf. die Oberkante des 2137 // naechsten Rahmen erreicht wird. 2138 // Insbesondere bei HTML-Dokumenten kommen oft (Dummy-)Absaetze in einer 2139 // 2-Pt.-Schrift vor, bis diese einem groesseren Rahmen ausgewichen sind, 2140 // erforderte es frueher Unmengen von Leerzeilen. 2141 const long nTmpTop = (aTmp.*fnRect->fnGetTop)(); 2142 if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 ) 2143 { 2144 if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 ) 2145 SetNextTop( nTmpTop ); // Die Oberkante des "naechsten" Rahmens 2146 } 2147 else if( ! (aTmp.*fnRect->fnGetWidth)() ) // Typisch fuer Objekte mit Konturumlauf 2148 { // Bei Objekten mit Konturumlauf, die vor der aktuellen Zeile beginnen 2149 // und hinter ihr enden, trotzdem aber nicht mit ihr ueberlappen, 2150 // muss die Optimierung ausgeschaltet werden, denn bereits in der 2151 // naechsten Zeile kann sich dies aendern. 2152 if( ! (aTmp.*fnRect->fnGetHeight)() || 2153 (*fnRect->fnYDiff)( (aTmp.*fnRect->fnGetBottom)(), 2154 (aLine.*fnRect->fnGetTop)() ) > 0 ) 2155 SetNextTop( 0 ); 2156 } 2157 if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight ) 2158 { 2159 nFlyRight = nTmpRight; 2160 if( SURROUND_RIGHT == eSurroundForTextWrap || 2161 SURROUND_PARALLEL == eSurroundForTextWrap ) 2162 { 2163 // der FlyFrm wird ueberstimmt. 2164 if( nRight > nFlyRight ) 2165 nRight = nFlyRight; 2166 bStop = sal_True; 2167 } 2168 } 2169 } 2170 (rFly.*fnRect->fnSetRight)( nRight ); 2171 } 2172 // <-- 2173 2174 /************************************************************************* 2175 * SwTxtFly::CalcLeftMargin() 2176 * 2177 * pFly ist der FlyFrm, der uns gerade ueberlappt. 2178 * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird. 2179 * Der linke Rand ist der linke Rand der aktuellen PrintArea oder 2180 * er wird durch den vorigen FlyFrm, der in die Zeile ragt, bestimmt. 2181 *************************************************************************/ 2182 // --> OD 2006-08-15 #i68520# 2183 void SwTxtFly::CalcLeftMargin( SwRect &rFly, 2184 SwAnchoredObjList::size_type nFlyPos, 2185 const SwRect &rLine ) const 2186 { 2187 ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(), 2188 "SwTxtFly::CalcLeftMargin with swapped frame" ) 2189 SWRECTFN( pCurrFrm ) 2190 // --> OD 2004-12-14 #118796# - correct determination of left of printing area 2191 SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)(); 2192 // <-- 2193 const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)(); 2194 2195 if( nLeft > nFlyLeft ) 2196 nLeft = rFly.Left(); 2197 2198 SwRect aLine( rLine ); 2199 (aLine.*fnRect->fnSetLeft)( nLeft ); 2200 2201 // Es koennte aber sein, dass in die gleiche Zeile noch ein anderes 2202 // Object hineinragt, welches _ueber_ uns liegt. 2203 // Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden 2204 // unsichtbar, das heisst, dass sie bei der Berechnung der Raender 2205 // anderer Flys ebenfalls nicht auffallen. 2206 // 3301: pNext->Frm().IsOver( rLine ) ist noetig 2207 2208 // --> OD 2006-08-15 #i68520# 2209 SwAnchoredObjList::size_type nMyPos = nFlyPos; 2210 while( ++nFlyPos < mpAnchoredObjList->size() ) 2211 // <-- 2212 { 2213 // --> OD 2006-08-15 #i68520# 2214 const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ]; 2215 const SwRect aTmp( pNext->GetObjRectWithSpaces() ); 2216 // <-- 2217 if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft ) 2218 break; 2219 } 2220 2221 while( nFlyPos ) 2222 { 2223 if( --nFlyPos == nMyPos ) 2224 continue; 2225 // --> OD 2006-08-15 #i68520# 2226 const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ]; 2227 if( pNext == mpCurrAnchoredObj ) 2228 continue; 2229 SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext ); 2230 if( SURROUND_THROUGHT == eSurroundForTextWrap ) 2231 continue; 2232 // <-- 2233 2234 const SwRect aTmp( SwContourCache::CalcBoundRect 2235 ( pNext, aLine, pCurrFrm, nFlyLeft, sal_False ) ); 2236 2237 if( (aTmp.*fnRect->fnGetLeft)() < nFlyLeft && aTmp.IsOver( aLine ) ) 2238 { 2239 // --> OD 2004-12-14 #118796# - no '+1', because <..fnGetRight> 2240 // returns the correct value. 2241 SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)(); 2242 if ( nLeft <= nTmpRight ) 2243 nLeft = nTmpRight; 2244 // <-- 2245 2246 break; 2247 } 2248 } 2249 (rFly.*fnRect->fnSetLeft)( nLeft ); 2250 } 2251 // <-- 2252 2253 /************************************************************************* 2254 * SwTxtFly::FlyToRect() 2255 * 2256 * IN: dokumentglobal (rRect) 2257 * OUT: dokumentglobal (return-Wert) 2258 * Liefert zu einem SwFlyFrm das von ihm in Anspruch genommene Rechteck 2259 * unter Beruecksichtigung der eingestellten Attribute fuer den Abstand 2260 * zum Text zurueck. 2261 *************************************************************************/ 2262 // --> OD 2006-08-15 #i68520# 2263 SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj, 2264 const SwRect &rLine ) const 2265 { 2266 SWRECTFN( pCurrFrm ) 2267 2268 const long nXPos = pCurrFrm->IsRightToLeft() ? 2269 rLine.Right() : 2270 (rLine.*fnRect->fnGetLeft)(); 2271 2272 SwRect aFly = mbIgnoreContour ? 2273 pAnchoredObj->GetObjRectWithSpaces() : 2274 SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm, 2275 nXPos, ! pCurrFrm->IsRightToLeft() ); 2276 2277 if( !aFly.Width() ) 2278 return aFly; 2279 2280 SetNextTop( (aFly.*fnRect->fnGetBottom)() ); // Damit die Zeile ggf. bis zur Unterkante 2281 // des Rahmens waechst. 2282 SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj ); 2283 2284 // Bei LEFT und RIGHT vergroessern wir das Rechteck. 2285 // Hier gibt es einige Probleme, wenn mehrere Frames zu sehen sind. 2286 // Zur Zeit wird nur der einfachste Fall angenommen: 2287 // LEFT bedeutet, dass der Text links vom Frame fliessen soll, 2288 // d.h. der Frame blaeht sich bis zum rechten Rand der Printarea 2289 // oder bis zum naechsten Frame auf. 2290 // Bei RIGHT ist es umgekehrt. 2291 // Ansonsten wird immer der eingestellte Abstand zwischen Text 2292 // und Frame aufaddiert. 2293 switch( _GetSurroundForTextWrap( pAnchoredObj ) ) 2294 { 2295 case SURROUND_LEFT : 2296 { 2297 CalcRightMargin( aFly, nFlyPos, rLine ); 2298 break; 2299 } 2300 case SURROUND_RIGHT : 2301 { 2302 CalcLeftMargin( aFly, nFlyPos, rLine ); 2303 break; 2304 } 2305 case SURROUND_NONE : 2306 { 2307 CalcRightMargin( aFly, nFlyPos, rLine ); 2308 CalcLeftMargin( aFly, nFlyPos, rLine ); 2309 break; 2310 } 2311 default: 2312 break; 2313 } 2314 return aFly; 2315 } 2316 2317 // --> OD 2006-08-15 #i68520# 2318 // new method <_GetSurroundForTextWrap(..)> replaces methods 2319 // <CalcSmart(..)> and <GetOrder(..)> 2320 /************************************************************************* 2321 * SwTxtFly::CalcSmart() 2322 * 2323 * CalcSmart() liefert die Umlaufform zurueck. 2324 * 2325 * Auf beiden Seiten ist weniger als 2 cm Platz fuer den Text 2326 * => kein Umlauf ( SURROUND_NONE ) 2327 * Auf genau einer Seite ist mehr als 2 cm Platz 2328 * => Umlauf auf dieser Seite ( SURROUND_LEFT / SURROUND_RIGHT ) 2329 * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist breiter als 1,5 cm 2330 * => Umlauf auf der breiteren Seite ( SURROUND_LEFT / SURROUND_RIGHT ) 2331 * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist schmaler als 1,5 cm 2332 * => beidseitiger Umlauf ( SURROUND_PARALLEL ) 2333 * 2334 *************************************************************************/ 2335 2336 // Umfluss nur auf Seiten mit mindestens 2 cm Platz fuer den Text 2337 #define TEXT_MIN 1134 2338 // Beidseitiger Umfluss bis zu einer Rahmenbreite von maximal 1,5 cm 2339 #define FRAME_MAX 850 2340 2341 SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const 2342 { 2343 const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt()); 2344 const SwFmtSurround &rFlyFmt = pFmt->GetSurround(); 2345 SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround(); 2346 2347 if( rFlyFmt.IsAnchorOnly() && pAnchoredObj->GetAnchorFrm() != GetMaster() ) 2348 { 2349 const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); 2350 if ((FLY_AT_PARA == rAnchor.GetAnchorId()) || 2351 (FLY_AT_CHAR == rAnchor.GetAnchorId())) 2352 { 2353 return SURROUND_NONE; 2354 } 2355 } 2356 2357 // Beim Durchlauf und Nowrap wird smart ignoriert. 2358 if( SURROUND_THROUGHT == eSurroundForTextWrap || 2359 SURROUND_NONE == eSurroundForTextWrap ) 2360 return eSurroundForTextWrap; 2361 2362 // left is left and right is right 2363 if ( pCurrFrm->IsRightToLeft() ) 2364 { 2365 if ( SURROUND_LEFT == eSurroundForTextWrap ) 2366 eSurroundForTextWrap = SURROUND_RIGHT; 2367 else if ( SURROUND_RIGHT == eSurroundForTextWrap ) 2368 eSurroundForTextWrap = SURROUND_LEFT; 2369 } 2370 2371 // "idealer Seitenumlauf": 2372 if ( SURROUND_IDEAL == eSurroundForTextWrap ) 2373 { 2374 SWRECTFN( pCurrFrm ) 2375 const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)(); 2376 const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)(); 2377 const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() ); 2378 long nFlyLeft = (aRect.*fnRect->fnGetLeft)(); 2379 long nFlyRight = (aRect.*fnRect->fnGetRight)(); 2380 2381 if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight ) 2382 eSurroundForTextWrap = SURROUND_PARALLEL; 2383 else 2384 { 2385 long nLeft = nFlyLeft - nCurrLeft; 2386 long nRight = nCurrRight - nFlyRight; 2387 if( nFlyRight - nFlyLeft > FRAME_MAX ) 2388 { 2389 if( nLeft < nRight ) 2390 nLeft = 0; 2391 else 2392 nRight = 0; 2393 } 2394 if( nLeft < TEXT_MIN ) 2395 nLeft = 0; 2396 if( nRight < TEXT_MIN ) 2397 nRight = 0; 2398 if( nLeft ) 2399 eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT; 2400 else 2401 eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE; 2402 } 2403 } 2404 2405 return eSurroundForTextWrap; 2406 } 2407 2408 /************************************************************************* 2409 * SwTxtFly::IsAnyFrm( SwRect ) 2410 * 2411 * IN: dokumentglobal 2412 * 2413 * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax) 2414 * 2415 *************************************************************************/ 2416 2417 sal_Bool SwTxtFly::IsAnyFrm( const SwRect &rLine ) const 2418 { 2419 2420 SWAP_IF_SWAPPED( pCurrFrm ) 2421 2422 ASSERT( bOn, "IsAnyFrm: Why?" ); 2423 2424 const sal_Bool bRet = ForEach( rLine, NULL, sal_False ); 2425 UNDO_SWAP( pCurrFrm ) 2426 return bRet; 2427 } 2428