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