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 28 #include <hintids.hxx> 29 #include <vcl/metric.hxx> 30 #include <vcl/window.hxx> 31 #include <vcl/svapp.hxx> 32 #include <paratr.hxx> 33 #include <txtfrm.hxx> // Format() 34 #include <charfmt.hxx> 35 #include <viewopt.hxx> // SwViewOption 36 #include <viewsh.hxx> // ViewShell 37 #include <pordrop.hxx> 38 #include <itrform2.hxx> 39 #include <txtpaint.hxx> // SwSaveClip 40 #include <blink.hxx> // pBlink 41 #include <breakit.hxx> 42 #include <com/sun/star/i18n/ScriptType.hdl> 43 #include <com/sun/star/i18n/WordType.hpp> 44 #include <editeng/langitem.hxx> 45 #include <charatr.hxx> 46 #include <editeng/fhgtitem.hxx> 47 #include <switerator.hxx> 48 49 using namespace ::com::sun::star::i18n; 50 using namespace ::com::sun::star; 51 52 /************************************************************************* 53 * lcl_IsDropFlyInter 54 * 55 * Calculates if a drop caps portion intersects with a fly 56 * The width and height of the drop caps portion are passed as arguments, 57 * the position is calculated from the values in rInf 58 *************************************************************************/ 59 60 sal_Bool lcl_IsDropFlyInter( const SwTxtFormatInfo &rInf, 61 sal_uInt16 nWidth, sal_uInt16 nHeight ) 62 { 63 const SwTxtFly *pTxtFly = rInf.GetTxtFly(); 64 if( pTxtFly && pTxtFly->IsOn() ) 65 { 66 SwRect aRect( rInf.GetTxtFrm()->Frm().Pos(), Size( nWidth, nHeight) ); 67 aRect.Pos() += rInf.GetTxtFrm()->Prt().Pos(); 68 aRect.Pos().X() += rInf.X(); 69 aRect.Pos().Y() = rInf.Y(); 70 aRect = pTxtFly->GetFrm( aRect ); 71 return aRect.HasArea(); 72 } 73 74 return sal_False; 75 } 76 77 /************************************************************************* 78 * class SwDropSave 79 *************************************************************************/ 80 81 class SwDropSave 82 { 83 SwTxtPaintInfo* pInf; 84 xub_StrLen nIdx; 85 xub_StrLen nLen; 86 long nX; 87 long nY; 88 89 public: 90 SwDropSave( const SwTxtPaintInfo &rInf ); 91 ~SwDropSave(); 92 }; 93 94 SwDropSave::SwDropSave( const SwTxtPaintInfo &rInf ) : 95 pInf( ((SwTxtPaintInfo*)&rInf) ), nIdx( rInf.GetIdx() ), 96 nLen( rInf.GetLen() ), nX( rInf.X() ), nY( rInf.Y() ) 97 { 98 } 99 100 SwDropSave::~SwDropSave() 101 { 102 pInf->SetIdx( nIdx ); 103 pInf->SetLen( nLen ); 104 pInf->X( nX ); 105 pInf->Y( nY ); 106 } 107 108 /************************************************************************* 109 * SwDropPortionPart DTor 110 *************************************************************************/ 111 112 SwDropPortionPart::~SwDropPortionPart() 113 { 114 if ( pFollow ) 115 delete pFollow; 116 delete pFnt; 117 } 118 119 /************************************************************************* 120 * SwDropPortion CTor, DTor 121 *************************************************************************/ 122 123 SwDropPortion::SwDropPortion( const MSHORT nLineCnt, 124 const KSHORT nDrpHeight, 125 const KSHORT nDrpDescent, 126 const KSHORT nDist ) 127 : pPart( 0 ), 128 nLines( nLineCnt ), 129 nDropHeight(nDrpHeight), 130 nDropDescent(nDrpDescent), 131 nDistance(nDist), 132 nFix(0), 133 nX(0) 134 { 135 SetWhichPor( POR_DROP ); 136 } 137 138 SwDropPortion::~SwDropPortion() 139 { 140 delete pPart; 141 if( pBlink ) 142 pBlink->Delete( this ); 143 } 144 145 sal_Bool SwTxtSizeInfo::_HasHint( const SwTxtNode* pTxtNode, xub_StrLen nPos ) 146 { 147 return 0 != pTxtNode->GetTxtAttrForCharAt(nPos); 148 } 149 150 /************************************************************************* 151 * SwTxtNode::GetDropLen() 152 * 153 * nWishLen = 0 indicates that we want a whole word 154 *************************************************************************/ 155 156 MSHORT SwTxtNode::GetDropLen( MSHORT nWishLen ) const 157 { 158 xub_StrLen nEnd = GetTxt().Len(); 159 if( nWishLen && nWishLen < nEnd ) 160 nEnd = nWishLen; 161 162 if ( ! nWishLen && pBreakIt->GetBreakIter().is() ) 163 { 164 // find first word 165 const SwAttrSet& rAttrSet = GetSwAttrSet(); 166 const sal_uInt16 nTxtScript = pBreakIt->GetRealScriptOfText( GetTxt(), 0 ); 167 168 LanguageType eLanguage; 169 170 switch ( nTxtScript ) 171 { 172 case i18n::ScriptType::ASIAN : 173 eLanguage = rAttrSet.GetCJKLanguage().GetLanguage(); 174 break; 175 case i18n::ScriptType::COMPLEX : 176 eLanguage = rAttrSet.GetCTLLanguage().GetLanguage(); 177 break; 178 default : 179 eLanguage = rAttrSet.GetLanguage().GetLanguage(); 180 break; 181 } 182 183 Boundary aBound = 184 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), 0, 185 pBreakIt->GetLocale( eLanguage ), WordType::DICTIONARY_WORD, sal_True ); 186 187 nEnd = (xub_StrLen)aBound.endPos; 188 } 189 190 xub_StrLen i = 0; 191 for( ; i < nEnd; ++i ) 192 { 193 xub_Unicode cChar = GetTxt().GetChar( i ); 194 if( CH_TAB == cChar || CH_BREAK == cChar || 195 (( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar ) 196 && SwTxtSizeInfo::_HasHint( this, i ) ) ) 197 break; 198 } 199 return i; 200 } 201 202 /************************************************************************* 203 * SwTxtNode::GetDropSize() 204 * 205 * If a dropcap is found the return value is true otherwise false. The 206 * drop cap sizes passed back by reference are font height, drop height 207 * and drop descent. 208 *************************************************************************/ 209 bool SwTxtNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const 210 { 211 rFontHeight = 0; 212 rDropHeight = 0; 213 rDropDescent =0; 214 215 const SwAttrSet& rSet = GetSwAttrSet(); 216 const SwFmtDrop& rDrop = rSet.GetDrop(); 217 218 // Return (0,0) if there is no drop cap at this paragraph 219 if( 1 >= rDrop.GetLines() || 220 ( !rDrop.GetChars() && !rDrop.GetWholeWord() ) ) 221 { 222 return false; 223 } 224 225 // get text frame 226 SwIterator<SwTxtFrm,SwTxtNode> aIter( *this ); 227 for( SwTxtFrm* pLastFrm = aIter.First(); pLastFrm; pLastFrm = aIter.Next() ) 228 { 229 // Only (master-) text frames can have a drop cap. 230 if ( !pLastFrm->IsFollow() ) 231 { 232 233 if( !pLastFrm->HasPara() ) 234 pLastFrm->GetFormatted(); 235 236 if ( !pLastFrm->IsEmpty() ) 237 { 238 const SwParaPortion* pPara = pLastFrm->GetPara(); 239 ASSERT( pPara, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" ) 240 241 if ( pPara ) 242 { 243 const SwLinePortion* pFirstPor = pPara->GetFirstPortion(); 244 if (pFirstPor && pFirstPor->IsDropPortion()) 245 { 246 const SwDropPortion* pDrop = (const SwDropPortion*)pFirstPor; 247 rDropHeight = pDrop->GetDropHeight(); 248 rDropDescent = pDrop->GetDropDescent(); 249 if (const SwFont *pFont = pDrop->GetFnt()) 250 rFontHeight = pFont->GetSize(pFont->GetActual()).Height(); 251 else 252 { 253 const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get(RES_CHRATR_FONTSIZE); 254 rFontHeight = rItem.GetHeight(); 255 } 256 } 257 } 258 } 259 break; 260 } 261 } 262 263 if (rFontHeight==0 && rDropHeight==0 && rDropDescent==0) 264 { 265 const sal_uInt16 nLines = rDrop.GetLines(); 266 267 const SvxFontHeightItem& rItem = (SvxFontHeightItem&)rSet.Get( RES_CHRATR_FONTSIZE ); 268 rFontHeight = rItem.GetHeight(); 269 rDropHeight = nLines * rFontHeight; 270 rDropDescent = rFontHeight / 5; 271 return false; 272 } 273 274 return true; 275 } 276 277 /************************************************************************* 278 * SwDropPortion::PaintTxt() 279 *************************************************************************/ 280 281 // Die Breite manipulieren, sonst werden die Buchstaben gestretcht 282 283 void SwDropPortion::PaintTxt( const SwTxtPaintInfo &rInf ) const 284 { 285 if ( rInf.OnWin() && 286 !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() ) 287 rInf.DrawBackground( *this ); 288 289 ASSERT( nDropHeight && pPart && nLines != 1, "Drop Portion painted twice" ); 290 291 const SwDropPortionPart* pCurrPart = GetPart(); 292 const xub_StrLen nOldLen = GetLen(); 293 294 const SwTwips nBasePosY = rInf.Y(); 295 ((SwTxtPaintInfo&)rInf).Y( nBasePosY + nY ); 296 SwDropSave aSave( rInf ); 297 // for text inside drop portions we let vcl handle the text directions 298 SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() ); 299 aLayoutModeModifier.SetAuto(); 300 301 while ( pCurrPart ) 302 { 303 ((SwDropPortion*)this)->SetLen( pCurrPart->GetLen() ); 304 ((SwTxtPaintInfo&)rInf).SetLen( pCurrPart->GetLen() ); 305 SwFontSave aFontSave( rInf, &pCurrPart->GetFont() ); 306 307 SwTxtPortion::Paint( rInf ); 308 309 ((SwTxtPaintInfo&)rInf).SetIdx( rInf.GetIdx() + pCurrPart->GetLen() ); 310 ((SwTxtPaintInfo&)rInf).X( rInf.X() + pCurrPart->GetWidth() ); 311 pCurrPart = pCurrPart->GetFollow(); 312 } 313 314 ((SwTxtPaintInfo&)rInf).Y( nBasePosY ); 315 ((SwDropPortion*)this)->SetLen( nOldLen ); 316 } 317 318 /************************************************************************* 319 * SwDropPortion::Paint() 320 *************************************************************************/ 321 322 void SwDropPortion::PaintDrop( const SwTxtPaintInfo &rInf ) const 323 { 324 // ganz normale Ausgabe wird w?hrend des normalen Paints erledigt 325 if( ! nDropHeight || ! pPart || nLines == 1 ) 326 return; 327 328 // Luegenwerte einstellen! 329 const KSHORT nOldHeight = Height(); 330 const KSHORT nOldWidth = Width(); 331 const KSHORT nOldAscent = GetAscent(); 332 const SwTwips nOldPosY = rInf.Y(); 333 const KSHORT nOldPosX = (KSHORT)rInf.X(); 334 const SwParaPortion *pPara = rInf.GetParaPortion(); 335 const Point aOutPos( nOldPosX + nX, nOldPosY - pPara->GetAscent() 336 - pPara->GetRealHeight() + pPara->Height() ); 337 // Retusche nachholen. 338 339 // Set baseline 340 ((SwTxtPaintInfo&)rInf).Y( aOutPos.Y() + nDropHeight ); 341 342 // for background 343 ((SwDropPortion*)this)->Height( nDropHeight + nDropDescent ); 344 ((SwDropPortion*)this)->Width( Width() - nX ); 345 ((SwDropPortion*)this)->SetAscent( nDropHeight ); 346 347 // Clipregion auf uns einstellen! 348 // Und zwar immer, und nie mit dem bestehenden ClipRect 349 // verrechnen, weil dies auf die Zeile eingestellt sein koennte. 350 351 SwRect aClipRect; 352 if ( rInf.OnWin() ) 353 { 354 aClipRect = SwRect( aOutPos, SvLSize() ); 355 aClipRect.Intersection( rInf.GetPaintRect() ); 356 } 357 SwSaveClip aClip( (OutputDevice*)rInf.GetOut() ); 358 aClip.ChgClip( aClipRect, rInf.GetTxtFrm() ); 359 // Das machen, was man sonst nur macht ... 360 PaintTxt( rInf ); 361 362 // Alte Werte sichern 363 ((SwDropPortion*)this)->Height( nOldHeight ); 364 ((SwDropPortion*)this)->Width( nOldWidth ); 365 ((SwDropPortion*)this)->SetAscent( nOldAscent ); 366 ((SwTxtPaintInfo&)rInf).Y( nOldPosY ); 367 } 368 369 /************************************************************************* 370 * virtual SwDropPortion::Paint() 371 *************************************************************************/ 372 373 void SwDropPortion::Paint( const SwTxtPaintInfo &rInf ) const 374 { 375 // ganz normale Ausgabe wird hier erledigt. 376 if( ! nDropHeight || ! pPart || 1 == nLines ) 377 { 378 if ( rInf.OnWin() && 379 !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() ) 380 rInf.DrawBackground( *this ); 381 382 // make sure that font is not rotated 383 SwFont* pTmpFont = 0; 384 if ( rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() ) ) 385 { 386 pTmpFont = new SwFont( *rInf.GetFont() ); 387 pTmpFont->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() ); 388 } 389 390 SwFontSave aFontSave( rInf, pTmpFont ); 391 // for text inside drop portions we let vcl handle the text directions 392 SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() ); 393 aLayoutModeModifier.SetAuto(); 394 395 SwTxtPortion::Paint( rInf ); 396 delete pTmpFont; 397 } 398 } 399 400 /************************************************************************* 401 * virtual Format() 402 *************************************************************************/ 403 404 405 sal_Bool SwDropPortion::FormatTxt( SwTxtFormatInfo &rInf ) 406 { 407 const xub_StrLen nOldLen = GetLen(); 408 const xub_StrLen nOldInfLen = rInf.GetLen(); 409 const sal_Bool bFull = SwTxtPortion::Format( rInf ); 410 if( bFull ) 411 { 412 // sieht zwar Scheisse aus, aber was soll man schon machen? 413 rInf.SetUnderFlow( 0 ); 414 Truncate(); 415 SetLen( nOldLen ); 416 rInf.SetLen( nOldInfLen ); 417 } 418 return bFull; 419 } 420 421 /************************************************************************* 422 * virtual GetTxtSize() 423 *************************************************************************/ 424 425 426 SwPosSize SwDropPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 427 { 428 sal_uInt16 nMyX = 0; 429 xub_StrLen nIdx = 0; 430 431 const SwDropPortionPart* pCurrPart = GetPart(); 432 433 // skip parts 434 while ( pCurrPart && nIdx + pCurrPart->GetLen() < rInf.GetLen() ) 435 { 436 nMyX = nMyX + pCurrPart->GetWidth(); 437 nIdx = nIdx + pCurrPart->GetLen(); 438 pCurrPart = pCurrPart->GetFollow(); 439 } 440 441 xub_StrLen nOldIdx = rInf.GetIdx(); 442 xub_StrLen nOldLen = rInf.GetLen(); 443 444 ((SwTxtSizeInfo&)rInf).SetIdx( nIdx ); 445 ((SwTxtSizeInfo&)rInf).SetLen( rInf.GetLen() - nIdx ); 446 447 // robust 448 SwFontSave aFontSave( rInf, pCurrPart ? &pCurrPart->GetFont() : 0 ); 449 SwPosSize aPosSize( SwTxtPortion::GetTxtSize( rInf ) ); 450 aPosSize.Width( aPosSize.Width() + nMyX ); 451 452 ((SwTxtSizeInfo&)rInf).SetIdx( nOldIdx ); 453 ((SwTxtSizeInfo&)rInf).SetLen( nOldLen ); 454 455 return aPosSize; 456 } 457 458 /************************************************************************* 459 * virtual GetCrsrOfst() 460 *************************************************************************/ 461 462 xub_StrLen SwDropPortion::GetCrsrOfst( const KSHORT ) const 463 { 464 return 0; 465 } 466 467 /************************************************************************* 468 * SwTxtFormatter::CalcDropHeight() 469 *************************************************************************/ 470 471 void SwTxtFormatter::CalcDropHeight( const MSHORT nLines ) 472 { 473 const SwLinePortion *const pOldCurr = GetCurr(); 474 KSHORT nDropHght = 0; 475 KSHORT nAscent = 0; 476 KSHORT nHeight = 0; 477 KSHORT nDropLns = 0; 478 sal_Bool bRegisterOld = IsRegisterOn(); 479 bRegisterOn = sal_False; 480 481 Top(); 482 483 while( GetCurr()->IsDummy() ) 484 { 485 if ( !Next() ) 486 break; 487 } 488 489 // Wenn wir nur eine Zeile haben returnen wir 0 490 if( GetNext() || GetDropLines() == 1 ) 491 { 492 for( ; nDropLns < nLines; nDropLns++ ) 493 { 494 if ( GetCurr()->IsDummy() ) 495 break; 496 else 497 { 498 CalcAscentAndHeight( nAscent, nHeight ); 499 nDropHght = nDropHght + nHeight; 500 bRegisterOn = bRegisterOld; 501 } 502 if ( !Next() ) 503 { 504 nDropLns++; // Fix: 11356 505 break; 506 } 507 } 508 509 // In der letzten Zeile plumpsen wir auf den Zeilenascent! 510 nDropHght = nDropHght - nHeight; 511 nDropHght = nDropHght + nAscent; 512 Top(); 513 } 514 bRegisterOn = bRegisterOld; 515 SetDropDescent( nHeight - nAscent ); 516 SetDropHeight( nDropHght ); 517 SetDropLines( nDropLns ); 518 // Alte Stelle wiederfinden! 519 while( pOldCurr != GetCurr() ) 520 { 521 if( !Next() ) 522 { 523 ASSERT( sal_False, "SwTxtFormatter::_CalcDropHeight: left Toulouse" ); 524 break; 525 } 526 } 527 } 528 529 /************************************************************************* 530 * SwTxtFormatter::GuessDropHeight() 531 * 532 * Wir schaetzen mal, dass die Fonthoehe sich nicht aendert und dass 533 * erst mindestens soviele Zeilen gibt, wie die DropCap-Einstellung angibt. 534 * 535 *************************************************************************/ 536 537 538 539 void SwTxtFormatter::GuessDropHeight( const MSHORT nLines ) 540 { 541 ASSERT( nLines, "GuessDropHeight: Give me more Lines!" ); 542 KSHORT nAscent = 0; 543 KSHORT nHeight = 0; 544 SetDropLines( nLines ); 545 if ( GetDropLines() > 1 ) 546 { 547 CalcRealHeight(); 548 CalcAscentAndHeight( nAscent, nHeight ); 549 } 550 SetDropDescent( nHeight - nAscent ); 551 SetDropHeight( nHeight * nLines - GetDropDescent() ); 552 } 553 554 /************************************************************************* 555 * SwTxtFormatter::NewDropPortion 556 *************************************************************************/ 557 558 SwDropPortion *SwTxtFormatter::NewDropPortion( SwTxtFormatInfo &rInf ) 559 { 560 if( !pDropFmt ) 561 return 0; 562 563 xub_StrLen nPorLen = pDropFmt->GetWholeWord() ? 0 : pDropFmt->GetChars(); 564 nPorLen = pFrm->GetTxtNode()->GetDropLen( nPorLen ); 565 if( !nPorLen ) 566 { 567 ((SwTxtFormatter*)this)->ClearDropFmt(); 568 return 0; 569 } 570 571 SwDropPortion *pDropPor = 0; 572 573 // erste oder zweite Runde? 574 if ( !( GetDropHeight() || IsOnceMore() ) ) 575 { 576 if ( GetNext() ) 577 CalcDropHeight( pDropFmt->GetLines() ); 578 else 579 GuessDropHeight( pDropFmt->GetLines() ); 580 } 581 582 // the DropPortion 583 if( GetDropHeight() ) 584 pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(), 585 GetDropDescent(), pDropFmt->GetDistance() ); 586 else 587 pDropPor = new SwDropPortion( 0,0,0,pDropFmt->GetDistance() ); 588 589 pDropPor->SetLen( nPorLen ); 590 591 // If it was not possible to create a proper drop cap portion 592 // due to avoiding endless loops. We return a drop cap portion 593 // with an empty SwDropCapPart. For these portions the current 594 // font is used. 595 if ( GetDropLines() < 2 ) 596 { 597 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True ); 598 return pDropPor; 599 } 600 601 // build DropPortionParts: 602 ASSERT( ! rInf.GetIdx(), "Drop Portion not at 0 position!" ); 603 xub_StrLen nNextChg = 0; 604 const SwCharFmt* pFmt = pDropFmt->GetCharFmt(); 605 SwDropPortionPart* pCurrPart = 0; 606 607 while ( nNextChg < nPorLen ) 608 { 609 // check for attribute changes and if the portion has to split: 610 Seek( nNextChg ); 611 612 // the font is deleted in the destructor of the drop portion part 613 SwFont* pTmpFnt = new SwFont( *rInf.GetFont() ); 614 if ( pFmt ) 615 { 616 const SwAttrSet& rSet = pFmt->GetAttrSet(); 617 pTmpFnt->SetDiffFnt( &rSet, pFrm->GetTxtNode()->getIDocumentSettingAccess() ); 618 } 619 620 // we do not allow a vertical font for the drop portion 621 pTmpFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() ); 622 623 // find next attribute change / script change 624 const xub_StrLen nTmpIdx = nNextChg; 625 xub_StrLen nNextAttr = Min( GetNextAttr(), rInf.GetTxt().Len() ); 626 nNextChg = pScriptInfo->NextScriptChg( nTmpIdx ); 627 if( nNextChg > nNextAttr ) 628 nNextChg = nNextAttr; 629 if ( nNextChg > nPorLen ) 630 nNextChg = nPorLen; 631 632 SwDropPortionPart* pPart = 633 new SwDropPortionPart( *pTmpFnt, nNextChg - nTmpIdx ); 634 635 if ( ! pCurrPart ) 636 pDropPor->SetPart( pPart ); 637 else 638 pCurrPart->SetFollow( pPart ); 639 640 pCurrPart = pPart; 641 } 642 643 ((SwTxtFormatter*)this)->SetPaintDrop( sal_True ); 644 return pDropPor; 645 } 646 647 /************************************************************************* 648 * SwTxtPainter::PaintDropPortion() 649 *************************************************************************/ 650 651 652 653 void SwTxtPainter::PaintDropPortion() 654 { 655 const SwDropPortion *pDrop = GetInfo().GetParaPortion()->FindDropPortion(); 656 ASSERT( pDrop, "DrapCop-Portion not available." ); 657 if( !pDrop ) 658 return; 659 660 const SwTwips nOldY = GetInfo().Y(); 661 662 Top(); 663 664 GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() ); 665 GetInfo().ResetSpaceIdx(); 666 GetInfo().SetKanaComp( pCurr->GetpKanaComp() ); 667 GetInfo().ResetKanaIdx(); 668 669 // 8047: Drops und Dummies 670 while( !pCurr->GetLen() && Next() ) 671 ; 672 673 // MarginPortion und Adjustment! 674 const SwLinePortion *pPor = pCurr->GetFirstPortion(); 675 KSHORT nX = 0; 676 while( pPor && !pPor->IsDropPortion() ) 677 { 678 nX = nX + pPor->Width(); 679 pPor = pPor->GetPortion(); 680 } 681 Point aLineOrigin( GetTopLeft() ); 682 683 #ifdef NIE 684 // Retusche nachholen... 685 if( nX ) 686 { 687 const Point aPoint( Left(), Y() ); 688 const Size aSize( nX - 1, GetDropHeight()+GetDropDescent() ); 689 SwRect aRetouche( aPoint, aSize ); 690 GetInfo().DrawRect( aRetouche ); 691 } 692 #endif 693 694 aLineOrigin.X() += nX; 695 KSHORT nTmpAscent, nTmpHeight; 696 CalcAscentAndHeight( nTmpAscent, nTmpHeight ); 697 aLineOrigin.Y() += nTmpAscent; 698 GetInfo().SetIdx( GetStart() ); 699 GetInfo().SetPos( aLineOrigin ); 700 GetInfo().SetLen( pDrop->GetLen() ); 701 702 pDrop->PaintDrop( GetInfo() ); 703 704 GetInfo().Y( nOldY ); 705 } 706 707 /************************************************************************* 708 * clas SwDropCapCache 709 * 710 * Da die Berechnung der Fontgroesse der Initialen ein teures Geschaeft ist, 711 * wird dies durch einen DropCapCache geschleust. 712 *************************************************************************/ 713 714 #define DROP_CACHE_SIZE 10 715 716 class SwDropCapCache 717 { 718 long aMagicNo[ DROP_CACHE_SIZE ]; 719 XubString aTxt[ DROP_CACHE_SIZE ]; 720 sal_uInt16 aFactor[ DROP_CACHE_SIZE ]; 721 KSHORT aWishedHeight[ DROP_CACHE_SIZE ]; 722 short aDescent[ DROP_CACHE_SIZE ]; 723 MSHORT nIndex; 724 public: 725 SwDropCapCache(); 726 ~SwDropCapCache(){} 727 void CalcFontSize( SwDropPortion* pDrop, SwTxtFormatInfo &rInf ); 728 }; 729 730 /************************************************************************* 731 * SwDropCapCache Ctor / Dtor 732 *************************************************************************/ 733 734 SwDropCapCache::SwDropCapCache() : nIndex( 0 ) 735 { 736 memset( &aMagicNo, 0, sizeof(aMagicNo) ); 737 memset( &aWishedHeight, 0, sizeof(aWishedHeight) ); 738 } 739 740 void SwDropPortion::DeleteDropCapCache() 741 { 742 delete pDropCapCache; 743 } 744 745 /************************************************************************* 746 * SwDropCapCache::CalcFontSize 747 *************************************************************************/ 748 749 void SwDropCapCache::CalcFontSize( SwDropPortion* pDrop, SwTxtFormatInfo &rInf ) 750 { 751 const void* pFntNo = 0; 752 MSHORT nTmpIdx = 0; 753 754 ASSERT( pDrop->GetPart(),"DropPortion without part during font calculation"); 755 756 SwDropPortionPart* pCurrPart = pDrop->GetPart(); 757 const sal_Bool bUseCache = ! pCurrPart->GetFollow(); 758 xub_StrLen nIdx = rInf.GetIdx(); 759 XubString aStr( rInf.GetTxt(), nIdx, pCurrPart->GetLen() ); 760 761 long nAscent = 0; 762 long nDescent = 0; 763 long nFactor = -1; 764 765 if ( bUseCache ) 766 { 767 SwFont& rFnt = pCurrPart->GetFont(); 768 rFnt.ChkMagic( rInf.GetVsh(), rFnt.GetActual() ); 769 rFnt.GetMagic( pFntNo, nTmpIdx, rFnt.GetActual() ); 770 771 nTmpIdx = 0; 772 773 while( nTmpIdx < DROP_CACHE_SIZE && 774 ( aTxt[ nTmpIdx ] != aStr || aMagicNo[ nTmpIdx ] != long(pFntNo) || 775 aWishedHeight[ nTmpIdx ] != pDrop->GetDropHeight() ) ) 776 ++nTmpIdx; 777 } 778 779 // we have to calculate a new font scaling factor if 780 // 1. we did not find a scaling factor in the cache or 781 // 2. we are not allowed to use the cache because the drop portion 782 // consists of more than one part 783 if( nTmpIdx >= DROP_CACHE_SIZE || ! bUseCache ) 784 { 785 ++nIndex; 786 nIndex %= DROP_CACHE_SIZE; 787 nTmpIdx = nIndex; 788 789 long nWishedHeight = pDrop->GetDropHeight(); 790 791 // find out biggest font size for initial scaling factor 792 long nMaxFontHeight = 0; 793 while ( pCurrPart ) 794 { 795 const SwFont& rFnt = pCurrPart->GetFont(); 796 const long nCurrHeight = rFnt.GetHeight( rFnt.GetActual() ); 797 if ( nCurrHeight > nMaxFontHeight ) 798 nMaxFontHeight = nCurrHeight; 799 800 pCurrPart = pCurrPart->GetFollow(); 801 } 802 803 nFactor = ( 1000 * nWishedHeight ) / nMaxFontHeight; 804 805 if ( bUseCache ) 806 { 807 // save keys for cache 808 aMagicNo[ nTmpIdx ] = long(pFntNo); 809 aTxt[ nTmpIdx ] = aStr; 810 aWishedHeight[ nTmpIdx ] = KSHORT(nWishedHeight); 811 // save initial scaling factor 812 aFactor[ nTmpIdx ] = (sal_uInt16)nFactor; 813 } 814 815 sal_Bool bGrow = ( pDrop->GetLen() != 0 ); 816 817 // for growing control 818 long nMax = KSHRT_MAX; 819 long nMin = nFactor / 2; 820 #if OSL_DEBUG_LEVEL > 1 821 long nGrow = 0; 822 #endif 823 824 sal_Bool bWinUsed = sal_False; 825 Font aOldFnt; 826 MapMode aOldMap( MAP_TWIP ); 827 OutputDevice* pOut = rInf.GetOut(); 828 OutputDevice* pWin; 829 if( rInf.GetVsh() && rInf.GetVsh()->GetWin() ) 830 pWin = rInf.GetVsh()->GetWin(); 831 else 832 pWin = GetpApp()->GetDefaultDevice(); 833 834 while( bGrow ) 835 { 836 // reset pCurrPart to first part 837 pCurrPart = pDrop->GetPart(); 838 sal_Bool bFirstGlyphRect = sal_True; 839 sal_Bool bHaveGlyphRect = sal_False; 840 Rectangle aCommonRect, aRect; 841 842 while ( pCurrPart ) 843 { 844 // current font 845 SwFont& rFnt = pCurrPart->GetFont(); 846 847 // Get height including proportion 848 const sal_uInt16 nCurrHeight = 849 (sal_uInt16)rFnt.GetHeight( rFnt.GetActual() ); 850 851 // Get without proportion 852 const sal_uInt8 nOldProp = rFnt.GetPropr(); 853 rFnt.SetProportion( 100 ); 854 Size aOldSize = Size( 0, rFnt.GetHeight( rFnt.GetActual() ) ); 855 856 Size aNewSize( 0, ( nFactor * nCurrHeight ) / 1000 ); 857 rFnt.SetSize( aNewSize, rFnt.GetActual() ); 858 rFnt.ChgPhysFnt( rInf.GetVsh(), *pOut ); 859 860 nAscent = rFnt.GetAscent( rInf.GetVsh(), *pOut ); 861 862 // Wir besorgen uns das alle Buchstaben umfassende Rechteck: 863 bHaveGlyphRect = pOut->GetTextBoundRect( aRect, rInf.GetTxt(), 0, 864 nIdx, pCurrPart->GetLen() ) && 865 ! aRect.IsEmpty(); 866 867 if ( ! bHaveGlyphRect ) 868 { 869 // getting glyph boundaries failed for some reason, 870 // we take the window for calculating sizes 871 if ( pWin ) 872 { 873 if ( ! bWinUsed ) 874 { 875 bWinUsed = sal_True; 876 aOldMap = pWin->GetMapMode( ); 877 pWin->SetMapMode( MapMode( MAP_TWIP ) ); 878 aOldFnt = pWin->GetFont(); 879 } 880 pWin->SetFont( rFnt.GetActualFont() ); 881 882 bHaveGlyphRect = pWin->GetTextBoundRect( aRect, rInf.GetTxt(), 0, 883 nIdx, pCurrPart->GetLen() ) && 884 ! aRect.IsEmpty(); 885 } 886 if ( bHaveGlyphRect ) 887 { 888 FontMetric aWinMet( pWin->GetFontMetric() ); 889 nAscent = (KSHORT) aWinMet.GetAscent(); 890 } 891 else 892 // We do not have a window or our window could not 893 // give us glyph boundaries. 894 aRect = Rectangle( Point( 0, 0 ), Size( 0, nAscent ) ); 895 } 896 897 // Now we (hopefully) have a bounding rectangle for the 898 // glyphs of the current portion and the ascent of the current 899 // font 900 901 // reset font size and proportion 902 rFnt.SetSize( aOldSize, rFnt.GetActual() ); 903 rFnt.SetProportion( nOldProp ); 904 905 if ( bFirstGlyphRect ) 906 { 907 aCommonRect = aRect; 908 bFirstGlyphRect = sal_False; 909 } 910 else 911 aCommonRect.Union( aRect ); 912 913 nIdx = nIdx + pCurrPart->GetLen(); 914 pCurrPart = pCurrPart->GetFollow(); 915 } 916 917 // now we have a union ( aCommonRect ) of all glyphs with 918 // respect to a common baseline : 0 919 920 // get descent and ascent from union 921 if ( rInf.GetTxtFrm()->IsVertical() ) 922 { 923 nDescent = aCommonRect.Left(); 924 nAscent = aCommonRect.Right(); 925 926 if ( nDescent < 0 ) 927 nDescent = -nDescent; 928 } 929 else 930 { 931 nDescent = aCommonRect.Bottom(); 932 nAscent = aCommonRect.Top(); 933 } 934 if ( nAscent < 0 ) 935 nAscent = -nAscent; 936 937 const long nHght = nAscent + nDescent; 938 if ( nHght ) 939 { 940 if ( nHght > nWishedHeight ) 941 nMax = nFactor; 942 else 943 { 944 if ( bUseCache ) 945 aFactor[ nTmpIdx ] = (sal_uInt16)nFactor; 946 nMin = nFactor; 947 } 948 949 nFactor = ( nFactor * nWishedHeight ) / nHght; 950 bGrow = ( nFactor > nMin ) && ( nFactor < nMax ); 951 #if OSL_DEBUG_LEVEL > 1 952 if ( bGrow ) 953 nGrow++; 954 #endif 955 nIdx = rInf.GetIdx(); 956 } 957 else 958 bGrow = sal_False; 959 } 960 961 if ( bWinUsed ) 962 { 963 // reset window if it has been used 964 pWin->SetMapMode( aOldMap ); 965 pWin->SetFont( aOldFnt ); 966 } 967 968 if ( bUseCache ) 969 aDescent[ nTmpIdx ] = -short( nDescent ); 970 } 971 972 pCurrPart = pDrop->GetPart(); 973 974 // did made any new calculations or did we use the cache? 975 if ( -1 == nFactor ) 976 { 977 nFactor = aFactor[ nTmpIdx ]; 978 nDescent = aDescent[ nTmpIdx ]; 979 } 980 else 981 nDescent = -nDescent; 982 983 while ( pCurrPart ) 984 { 985 // scale current font 986 SwFont& rFnt = pCurrPart->GetFont(); 987 Size aNewSize( 0, ( nFactor * rFnt.GetHeight( rFnt.GetActual() ) ) / 1000 ); 988 989 const sal_uInt8 nOldProp = rFnt.GetPropr(); 990 rFnt.SetProportion( 100 ); 991 rFnt.SetSize( aNewSize, rFnt.GetActual() ); 992 rFnt.SetProportion( nOldProp ); 993 994 pCurrPart = pCurrPart->GetFollow(); 995 } 996 pDrop->SetY( (short)nDescent ); 997 } 998 999 /************************************************************************* 1000 * virtual Format() 1001 *************************************************************************/ 1002 1003 sal_Bool SwDropPortion::Format( SwTxtFormatInfo &rInf ) 1004 { 1005 sal_Bool bFull = sal_False; 1006 Fix( (sal_uInt16)rInf.X() ); 1007 1008 SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() ); 1009 aLayoutModeModifier.SetAuto(); 1010 1011 if( nDropHeight && pPart && nLines!=1 ) 1012 { 1013 if( !pDropCapCache ) 1014 pDropCapCache = new SwDropCapCache(); 1015 1016 // adjust font sizes to fit into the rectangle 1017 pDropCapCache->CalcFontSize( this, rInf ); 1018 1019 const long nOldX = rInf.X(); 1020 { 1021 SwDropSave aSave( rInf ); 1022 SwDropPortionPart* pCurrPart = pPart; 1023 1024 while ( pCurrPart ) 1025 { 1026 rInf.SetLen( pCurrPart->GetLen() ); 1027 SwFont& rFnt = pCurrPart->GetFont(); 1028 { 1029 SwFontSave aFontSave( rInf, &rFnt ); 1030 bFull = FormatTxt( rInf ); 1031 1032 if ( bFull ) 1033 break; 1034 } 1035 1036 const SwTwips nTmpWidth = 1037 ( InSpaceGrp() && rInf.GetSpaceAdd() ) ? 1038 Width() + CalcSpacing( rInf.GetSpaceAdd(), rInf ) : 1039 Width(); 1040 1041 // set values 1042 pCurrPart->SetWidth( (sal_uInt16)nTmpWidth ); 1043 1044 // Move 1045 rInf.SetIdx( rInf.GetIdx() + pCurrPart->GetLen() ); 1046 rInf.X( rInf.X() + nTmpWidth ); 1047 pCurrPart = pCurrPart->GetFollow(); 1048 } 1049 1050 Width( (sal_uInt16)(rInf.X() - nOldX) ); 1051 } 1052 1053 // reset my length 1054 SetLen( rInf.GetLen() ); 1055 1056 // 7631, 7633: bei Ueberlappungen mit Flys ist Schluss. 1057 if( ! bFull ) 1058 bFull = lcl_IsDropFlyInter( rInf, Width(), nDropHeight ); 1059 1060 if( bFull ) 1061 { 1062 // Durch FormatTxt kann nHeight auf 0 gesetzt worden sein 1063 if ( !Height() ) 1064 Height( rInf.GetTxtHeight() ); 1065 1066 // Jetzt noch einmal der ganze Spass 1067 nDropHeight = nLines = 0; 1068 delete pPart; 1069 pPart = NULL; 1070 1071 // meanwhile use normal formatting 1072 bFull = SwTxtPortion::Format( rInf ); 1073 } 1074 else 1075 rInf.SetDropInit( sal_True ); 1076 1077 Height( rInf.GetTxtHeight() ); 1078 SetAscent( rInf.GetAscent() ); 1079 } 1080 else 1081 bFull = SwTxtPortion::Format( rInf ); 1082 1083 if( bFull ) 1084 nDistance = 0; 1085 else 1086 { 1087 const KSHORT nWant = Width() + GetDistance(); 1088 const KSHORT nRest = (sal_uInt16)(rInf.Width() - rInf.X()); 1089 if( ( nWant > nRest ) || 1090 lcl_IsDropFlyInter( rInf, Width() + GetDistance(), nDropHeight ) ) 1091 nDistance = 0; 1092 1093 Width( Width() + nDistance ); 1094 } 1095 return bFull; 1096 } 1097 1098