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 34 #include <com/sun/star/i18n/ScriptType.hdl> 35 #include <vcl/graph.hxx> 36 #include <editeng/brshitem.hxx> 37 #include <vcl/metric.hxx> 38 #include <vcl/outdev.hxx> 39 #include <viewopt.hxx> // SwViewOptions 40 #include <txtcfg.hxx> 41 #include <SwPortionHandler.hxx> 42 #include <porlay.hxx> 43 #include <porfld.hxx> 44 #include <inftxt.hxx> 45 #include <blink.hxx> // pBlink 46 #include <frmtool.hxx> // DrawGraphic 47 #include <viewsh.hxx> 48 #include <docsh.hxx> 49 #include <doc.hxx> 50 #include "rootfrm.hxx" 51 #include <breakit.hxx> 52 #include <porrst.hxx> 53 #include <porftn.hxx> // SwFtnPortion 54 #include <accessibilityoptions.hxx> 55 #include <editeng/lrspitem.hxx> 56 57 #include <unicode/ubidi.h> 58 59 using namespace ::com::sun::star; 60 61 /************************************************************************* 62 * class SwFldPortion 63 *************************************************************************/ 64 65 SwLinePortion *SwFldPortion::Compress() 66 { return (GetLen() || aExpand.Len() || SwLinePortion::Compress()) ? this : 0; } 67 68 SwFldPortion *SwFldPortion::Clone( const XubString &rExpand ) const 69 { 70 SwFont *pNewFnt; 71 if( 0 != ( pNewFnt = pFnt ) ) 72 { 73 pNewFnt = new SwFont( *pFnt ); 74 } 75 // --> OD 2009-11-25 #i107143# 76 // pass placeholder property to created <SwFldPortion> instance. 77 SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder ); 78 // <-- 79 pClone->SetNextOffset( nNextOffset ); 80 pClone->m_bNoLength = this->m_bNoLength; 81 return pClone; 82 } 83 84 void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld ) 85 { 86 ASSERT( pFld, "TakeNextOffset: Missing Source" ); 87 nNextOffset = pFld->GetNextOffset(); 88 aExpand.Erase( 0, nNextOffset ); 89 bFollow = sal_True; 90 } 91 92 SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold ) 93 : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0), 94 bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold ) 95 , m_bNoLength( sal_False ) 96 { 97 SetWhichPor( POR_FLD ); 98 } 99 100 SwFldPortion::SwFldPortion( const SwFldPortion& rFld ) 101 : SwExpandPortion( rFld ), 102 aExpand( rFld.GetExp() ), 103 nNextOffset( rFld.GetNextOffset() ), 104 nNextScriptChg( rFld.GetNextScriptChg() ), 105 bFollow( rFld.IsFollow() ), 106 bLeft( rFld.IsLeft() ), 107 bHide( rFld.IsHide() ), 108 bCenter( rFld.IsCenter() ), 109 bHasFollow( rFld.HasFollow() ), 110 bPlaceHolder( rFld.bPlaceHolder ) 111 , m_bNoLength( rFld.m_bNoLength ) 112 { 113 if ( rFld.HasFont() ) 114 pFnt = new SwFont( *rFld.GetFont() ); 115 else 116 pFnt = 0; 117 118 SetWhichPor( POR_FLD ); 119 } 120 121 SwFldPortion::~SwFldPortion() 122 { 123 delete pFnt; 124 if( pBlink ) 125 pBlink->Delete( this ); 126 } 127 128 /************************************************************************* 129 * virtual SwFldPortion::GetViewWidth() 130 *************************************************************************/ 131 132 KSHORT SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const 133 { 134 // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten 135 // Moment errechnet werden: 136 SwFldPortion* pThis = (SwFldPortion*)this; 137 if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() && 138 !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() ) 139 { 140 if( !nViewWidth ) 141 pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width(); 142 } 143 else 144 pThis->nViewWidth = 0; 145 return nViewWidth; 146 } 147 148 /************************************************************************* 149 * virtual SwFldPortion::Format() 150 *************************************************************************/ 151 152 // 8653: in keinem Fall nur SetLen(0); 153 154 /************************************************************************* 155 * Hilfsklasse SwFldSlot 156 **************************************************************************/ 157 158 class SwFldSlot 159 { 160 const XubString *pOldTxt; 161 XubString aTxt; 162 xub_StrLen nIdx; 163 xub_StrLen nLen; 164 sal_Bool bOn; 165 SwTxtFormatInfo *pInf; 166 public: 167 SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor ); 168 ~SwFldSlot(); 169 }; 170 171 SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor ) 172 { 173 bOn = pPor->GetExpTxt( *pNew, aTxt ); 174 175 // Der Text wird ausgetauscht... 176 if( bOn ) 177 { 178 pInf = (SwTxtFormatInfo*)pNew; 179 nIdx = pInf->GetIdx(); 180 nLen = pInf->GetLen(); 181 pOldTxt = &(pInf->GetTxt()); 182 pInf->SetLen( aTxt.Len() ); 183 if( pPor->IsFollow() ) 184 { 185 pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() ); 186 pInf->SetIdx( 0 ); 187 } 188 else 189 { 190 XubString aTmp( aTxt ); 191 aTxt = *pOldTxt; 192 aTxt.Erase( nIdx, 1 ); 193 aTxt.Insert( aTmp, nIdx ); 194 } 195 pInf->SetTxt( aTxt ); 196 } 197 } 198 199 SwFldSlot::~SwFldSlot() 200 { 201 if( bOn ) 202 { 203 pInf->SetTxt( *pOldTxt ); 204 pInf->SetIdx( nIdx ); 205 pInf->SetLen( nLen ); 206 pInf->SetFakeLineStart( sal_False ); 207 } 208 } 209 210 void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf ) 211 { 212 String aTxt; 213 if( GetExpTxt( rInf, aTxt ) && aTxt.Len() && pBreakIt->GetBreakIter().is() ) 214 { 215 sal_uInt8 nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual(); 216 sal_uInt16 nScript; 217 { 218 nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 ); 219 xub_StrLen nChg = 0; 220 if( i18n::ScriptType::WEAK == nScript ) 221 { 222 nChg =(xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript); 223 if( nChg < aTxt.Len() ) 224 nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg ); 225 } 226 227 // 228 // nNextScriptChg will be evaluated during SwFldPortion::Format() 229 // 230 if ( nChg < aTxt.Len() ) 231 nNextScriptChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript ); 232 else 233 nNextScriptChg = aTxt.Len(); 234 235 } 236 sal_uInt8 nTmp; 237 switch ( nScript ) { 238 case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break; 239 case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break; 240 case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break; 241 default: nTmp = nActual; 242 } 243 244 // #i16354# Change script type for RTL text to CTL. 245 const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo(); 246 // --> OD 2009-01-29 #i98418# 247 // const sal_uInt8 nFldDir = IsNumberPortion() ? 248 const sal_uInt8 nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ? 249 rSI.GetDefaultDir() : 250 rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() ); 251 // <-- 252 if ( UBIDI_RTL == nFldDir ) 253 { 254 UErrorCode nError = U_ZERO_ERROR; 255 UBiDi* pBidi = ubidi_openSized( aTxt.Len(), 0, &nError ); 256 ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.GetBuffer()), aTxt.Len(), nFldDir, NULL, &nError ); 257 int32_t nEnd; 258 UBiDiLevel nCurrDir; 259 ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir ); 260 ubidi_close( pBidi ); 261 const xub_StrLen nNextDirChg = (xub_StrLen)nEnd; 262 nNextScriptChg = Min( nNextScriptChg, nNextDirChg ); 263 264 // #i89825# change the script type also to CTL 265 // if there is no strong LTR char in the LTR run (numbers) 266 if ( nCurrDir != UBIDI_RTL ) 267 { 268 nCurrDir = UBIDI_RTL; 269 for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx ) 270 { 271 UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx )); 272 if ( nCharDir == U_LEFT_TO_RIGHT || 273 nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || 274 nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) 275 { 276 nCurrDir = UBIDI_LTR; 277 break; 278 } 279 } 280 } 281 282 if ( nCurrDir == UBIDI_RTL ) 283 nTmp = SW_CTL; 284 } 285 286 // --> OD 2009-01-29 #i98418# 287 // keep determined script type for footnote portions as preferred script type. 288 // For footnote portions a font can not be created directly - see footnote 289 // portion format method. 290 // if( !IsFtnPortion() && nTmp != nActual ) 291 if ( IsFtnPortion() ) 292 { 293 dynamic_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp ); 294 } 295 else if ( nTmp != nActual ) 296 { 297 if( !pFnt ) 298 pFnt = new SwFont( *rInf.GetFont() ); 299 pFnt->SetActual( nTmp ); 300 } 301 // <-- 302 } 303 } 304 305 sal_Bool SwFldPortion::Format( SwTxtFormatInfo &rInf ) 306 { 307 // Scope wegen aDiffTxt::DTOR! 308 xub_StrLen nRest; 309 sal_Bool bFull; 310 sal_Bool bEOL = sal_False; 311 long nTxtRest = rInf.GetTxt().Len() - rInf.GetIdx(); 312 { 313 SwFldSlot aDiffTxt( &rInf, this ); 314 SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() ); 315 aLayoutModeModifier.SetAuto(); 316 317 // Field portion has to be split in several parts if 318 // 1. There are script/direction changes inside the field 319 // 2. There are portion breaks (tab, break) inside the field: 320 const xub_StrLen nOldFullLen = rInf.GetLen(); 321 xub_StrLen nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx(); 322 if ( nNextScriptChg < nFullLen ) 323 { 324 nFullLen = nNextScriptChg; 325 rInf.SetHookChar( 0 ); 326 } 327 rInf.SetLen( nFullLen ); 328 329 if ( STRING_LEN != rInf.GetUnderScorePos() && 330 rInf.GetUnderScorePos() > rInf.GetIdx() ) 331 rInf.SetUnderScorePos( rInf.GetIdx() ); 332 333 if( pFnt ) 334 pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() ); 335 336 SwFontSave aSave( rInf, pFnt ); 337 338 // 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge 339 // gesetzt und wird in nRest uebertragen. Ansonsten bleibt die 340 // Laenge erhalten und wuerde auch in nRest einfliessen! 341 SetLen(0); 342 const MSHORT nFollow = IsFollow() ? 0 : 1; 343 344 // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der 345 // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs) 346 // sal_False returnen wegen SetFull ... 347 if( !nFullLen ) 348 { 349 // nicht Init(), weil wir Hoehe und Ascent brauchen 350 Width(0); 351 bFull = rInf.Width() <= rInf.GetPos().X(); 352 } 353 else 354 { 355 xub_StrLen nOldLineStart = rInf.GetLineStart(); 356 if( IsFollow() ) 357 rInf.SetLineStart( 0 ); 358 rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow ); 359 360 // the height depending on the fields font is set, 361 // this is required for SwTxtGuess::Guess 362 Height( rInf.GetTxtHeight() ); 363 // If a kerning portion is inserted after our field portion, 364 // the ascent and height must be known 365 SetAscent( rInf.GetAscent() ); 366 bFull = SwTxtPortion::Format( rInf ); 367 rInf.SetNotEOL( sal_False ); 368 rInf.SetLineStart( nOldLineStart ); 369 } 370 xub_StrLen nTmpLen = GetLen(); 371 bEOL = !nTmpLen && nFollow && bFull; 372 nRest = nOldFullLen - nTmpLen; 373 374 // Das Zeichen wird in der ersten Portion gehalten. 375 // Unbedingt nach Format! 376 SetLen( (m_bNoLength) ? 0 : nFollow ); 377 378 if( nRest ) 379 { 380 // aExpand ist noch nicht gekuerzt worden, der neue Ofst 381 // ergibt sich durch nRest. 382 xub_StrLen nNextOfst = aExpand.Len() - nRest; 383 384 if ( IsQuoVadisPortion() ) 385 nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().Len(); 386 387 XubString aNew( aExpand, nNextOfst, STRING_LEN ); 388 aExpand.Erase( nNextOfst, STRING_LEN ); 389 390 // These characters should not be contained in the follow 391 // field portion. They are handled via the HookChar mechanism. 392 switch( aNew.GetChar( 0 )) 393 { 394 case CH_BREAK : bFull = sal_True; 395 // kein break; 396 case ' ' : 397 case CH_TAB : 398 case CHAR_HARDHYPHEN: // non-breaking hyphen 399 case CHAR_SOFTHYPHEN: 400 case CHAR_HARDBLANK: 401 // --> FME 2006-01-11 #i59759# Erase additional control 402 // characters from field string, otherwise we get stuck in 403 // a loop. 404 case CHAR_ZWSP : 405 case CHAR_ZWNBSP : 406 // case CHAR_RLM : 407 // case CHAR_LRM : 408 // <-- 409 // --> OD 2010-06-03 #i111750# 410 // - Erasing further control characters from field string in 411 // to avoid loop. 412 case CH_TXTATR_BREAKWORD: 413 case CH_TXTATR_INWORD: 414 // <-- 415 { 416 aNew.Erase( 0, 1 ); 417 ++nNextOfst; 418 break; 419 } 420 default: ; 421 } 422 423 // Even if there is no more text left for a follow field, 424 // we have to build a follow field portion (without font), 425 // otherwise the HookChar mechanism would not work. 426 SwFldPortion *pFld = Clone( aNew ); 427 if( aNew.Len() && !pFld->GetFont() ) 428 { 429 SwFont *pNewFnt = new SwFont( *rInf.GetFont() ); 430 pFld->SetFont( pNewFnt ); 431 } 432 pFld->SetFollow( sal_True ); 433 SetHasFollow( sal_True ); 434 // In nNextOffset steht bei einem neuangelegten Feld zunaechst 435 // der Offset, an dem es selbst im Originalstring beginnt. 436 // Wenn beim Formatieren ein FollowFeld angelegt wird, wird 437 // der Offset dieses FollowFelds in nNextOffset festgehalten. 438 nNextOffset = nNextOffset + nNextOfst; 439 pFld->SetNextOffset( nNextOffset ); 440 rInf.SetRest( pFld ); 441 } 442 } 443 444 if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() ) 445 rInf.GetLast()->FormatEOL( rInf ); 446 return bFull; 447 } 448 449 /************************************************************************* 450 * virtual SwFldPortion::Paint() 451 *************************************************************************/ 452 453 void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const 454 { 455 SwFontSave aSave( rInf, pFnt ); 456 457 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" ); 458 if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) ) 459 { 460 // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ... 461 rInf.DrawViewOpt( *this, POR_FLD ); 462 SwExpandPortion::Paint( rInf ); 463 } 464 } 465 466 /************************************************************************* 467 * virtual SwFldPortion::GetExpTxt() 468 *************************************************************************/ 469 470 sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 471 { 472 rTxt = aExpand; 473 if( !rTxt.Len() && rInf.OnWin() && 474 !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && 475 SwViewOption::IsFieldShadings() && 476 !HasFollow() ) 477 rTxt = ' '; 478 return sal_True; 479 } 480 481 /************************************************************************* 482 * virtual SwFldPortion::HandlePortion() 483 *************************************************************************/ 484 485 void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const 486 { 487 rPH.Special( GetLen(), aExpand, GetWhichPor() ); 488 } 489 490 /************************************************************************* 491 * virtual SwFldPortion::GetTxtSize() 492 *************************************************************************/ 493 494 SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 495 { 496 SwFontSave aSave( rInf, pFnt ); 497 SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) ); 498 return aSize; 499 } 500 501 /************************************************************************* 502 * class SwHiddenPortion 503 *************************************************************************/ 504 505 SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const 506 { 507 SwFont *pNewFnt; 508 if( 0 != ( pNewFnt = pFnt ) ) 509 pNewFnt = new SwFont( *pFnt ); 510 return new SwHiddenPortion( rExpand, pNewFnt ); 511 } 512 513 /************************************************************************* 514 * virtual SwHiddenPortion::Paint() 515 *************************************************************************/ 516 517 void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const 518 { 519 if( Width() ) 520 { 521 SwFontSave aSave( rInf, pFnt ); 522 rInf.DrawViewOpt( *this, POR_HIDDEN ); 523 SwExpandPortion::Paint( rInf ); 524 } 525 } 526 527 /************************************************************************* 528 * virtual SwHiddenPortion::GetExpTxt() 529 *************************************************************************/ 530 531 sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 532 { 533 // Nicht auf IsHidden() abfragen ! 534 return SwFldPortion::GetExpTxt( rInf, rTxt ); 535 } 536 537 /************************************************************************* 538 * class SwNumberPortion 539 *************************************************************************/ 540 541 // --> OD 2008-01-23 #newlistlevelattrs# 542 SwNumberPortion::SwNumberPortion( const XubString &rExpand, 543 SwFont *pFont, 544 const sal_Bool bLft, 545 const sal_Bool bCntr, 546 const KSHORT nMinDst, 547 const bool bLabelAlignmentPosAndSpaceModeActive ) 548 : SwFldPortion( rExpand, pFont ), 549 nFixWidth(0), 550 nMinDist( nMinDst ), 551 // --> OD 2008-01-23 #newlistlevelattrs# 552 mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive ) 553 // <-- 554 { 555 SetWhichPor( POR_NUMBER ); 556 SetLeft( bLft ); 557 SetHide( sal_False ); 558 SetCenter( bCntr ); 559 } 560 561 xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const 562 { 563 return 0; 564 } 565 566 SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const 567 { 568 SwFont *pNewFnt; 569 if( 0 != ( pNewFnt = pFnt ) ) 570 pNewFnt = new SwFont( *pFnt ); 571 // --> OD 2008-01-23 #newlistlevelattrs# 572 return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(), 573 nMinDist, mbLabelAlignmentPosAndSpaceModeActive ); 574 // <-- 575 } 576 577 /************************************************************************* 578 * virtual SwNumberPortion::Format() 579 *************************************************************************/ 580 581 // 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen! 582 // 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text 583 // eingibt, bis die Zeile ueberlaeuft. 584 // Man muss die Fly-Ausweichmanoever beachten! 585 586 sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf ) 587 { 588 SetHide( sal_False ); 589 const sal_Bool bFull = SwFldPortion::Format( rInf ); 590 SetLen( 0 ); 591 // a numbering portion can be contained in a rotated portion!!! 592 nFixWidth = rInf.IsMulti() ? Height() : Width(); 593 rInf.SetNumDone( !rInf.GetRest() ); 594 if( rInf.IsNumDone() ) 595 { 596 // SetAscent( rInf.GetAscent() ); 597 ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" ); 598 599 long nDiff( 0 ); 600 // --> OD 2008-01-23 #newlistlevelattrs# 601 if ( !mbLabelAlignmentPosAndSpaceModeActive ) 602 { 603 if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) && 604 // --> FME 2004-08-13 #i32902# 605 !IsFtnNumPortion() ) 606 // <-- 607 { 608 nDiff = rInf.Left() 609 + rInf.GetTxtFrm()->GetTxtNode()-> 610 GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst() 611 - rInf.First() 612 + rInf.ForcedLeftMargin(); 613 } 614 else 615 { 616 nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 617 } 618 } 619 // <-- 620 // Ein Vorschlag von Juergen und Volkmar: 621 // Der Textteil hinter der Numerierung sollte immer 622 // mindestens beim linken Rand beginnen. 623 if( nDiff < 0 ) 624 nDiff = 0; 625 else if ( nDiff > rInf.X() ) 626 nDiff -= rInf.X(); 627 else 628 nDiff = 0; 629 630 if( nDiff < nFixWidth + nMinDist ) 631 nDiff = nFixWidth + nMinDist; 632 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde 633 // fieser Sonderfall: FlyFrm liegt in dem Bereich, 634 // den wir uns gerade unter den Nagel reissen wollen. 635 // Die NumberPortion wird als verborgen markiert. 636 const sal_Bool bFly = rInf.GetFly() || 637 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() ); 638 if( nDiff > rInf.Width() ) 639 { 640 nDiff = rInf.Width(); 641 if ( bFly ) 642 SetHide( sal_True ); 643 } 644 645 // A numbering portion can be inside a SwRotatedPortion. Then the 646 // Height has to be changed 647 if ( rInf.IsMulti() ) 648 { 649 if ( Height() < nDiff ) 650 Height( KSHORT( nDiff ) ); 651 } 652 else if( Width() < nDiff ) 653 Width( KSHORT(nDiff) ); 654 } 655 return bFull; 656 } 657 658 void SwNumberPortion::FormatEOL( SwTxtFormatInfo& ) 659 { 660 /* Ein FormatEOL deutet daraufhin, dass der folgende Text 661 * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert, 662 * wird diese NumberPortion verborgen. 663 */ 664 665 // This caused trouble with flys anchored as characters. 666 // If one of these is numbered but does not fit to the line, 667 // it calls this function, causing a loop because both the number 668 // portion and the fly portion go to the next line 669 // SetHide( sal_True ); 670 } 671 672 /************************************************************************* 673 * virtual SwNumberPortion::Paint() 674 *************************************************************************/ 675 676 void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const 677 { 678 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt 679 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile. 680 */ 681 682 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() ) 683 { 684 SwLinePortion *pTmp = GetPortion(); 685 while ( pTmp && !pTmp->InTxtGrp() ) 686 pTmp = pTmp->GetPortion(); 687 if ( !pTmp ) 688 return; 689 } 690 691 // calculate the width of the number portion, including follows 692 const KSHORT nOldWidth = Width(); 693 sal_uInt16 nSumWidth = 0; 694 sal_uInt16 nOffset = 0; 695 696 const SwLinePortion* pTmp = this; 697 while ( pTmp && pTmp->InNumberGrp() ) 698 { 699 nSumWidth = nSumWidth + pTmp->Width(); 700 if ( ((SwNumberPortion*)pTmp)->HasFollow() ) 701 pTmp = pTmp->GetPortion(); 702 else 703 { 704 nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth; 705 break; 706 } 707 } 708 709 // The master portion takes care for painting the background of the 710 // follow field portions 711 if ( ! IsFollow() ) 712 { 713 SwLinePortion *pThis = (SwLinePortion*)this; 714 pThis->Width( nSumWidth ); 715 rInf.DrawViewOpt( *this, POR_NUMBER ); 716 pThis->Width( nOldWidth ); 717 } 718 719 if( aExpand.Len() ) 720 { 721 const SwFont *pTmpFnt = rInf.GetFont(); 722 sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() || 723 UNDERLINE_NONE != pTmpFnt->GetOverline() || 724 STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) && 725 !pTmpFnt->IsWordLineMode(); 726 if( bPaintSpace && pFnt ) 727 bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() || 728 UNDERLINE_NONE != pFnt->GetOverline() || 729 STRIKEOUT_NONE != pFnt->GetStrikeout() ) && 730 !pFnt->IsWordLineMode(); 731 732 SwFontSave aSave( rInf, pFnt ); 733 734 if( nFixWidth == Width() && ! HasFollow() ) 735 SwExpandPortion::Paint( rInf ); 736 else 737 { 738 // logisches const: Width wird wieder zurueckgesetzt 739 SwLinePortion *pThis = (SwLinePortion*)this; 740 bPaintSpace = bPaintSpace && nFixWidth < nOldWidth; 741 KSHORT nSpaceOffs = nFixWidth; 742 pThis->Width( nFixWidth ); 743 744 if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) || 745 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) ) 746 SwExpandPortion::Paint( rInf ); 747 else 748 { 749 SwTxtPaintInfo aInf( rInf ); 750 if( nOffset < nMinDist ) 751 nOffset = 0; 752 else 753 { 754 if( IsCenter() ) 755 { 756 /* #110778# a / 2 * 2 == a is not a tautology */ 757 KSHORT nTmpOffset = nOffset; 758 nOffset /= 2; 759 if( nOffset < nMinDist ) 760 nOffset = nTmpOffset - nMinDist; 761 } 762 else 763 nOffset = nOffset - nMinDist; 764 } 765 aInf.X( aInf.X() + nOffset ); 766 SwExpandPortion::Paint( aInf ); 767 if( bPaintSpace ) 768 nSpaceOffs = nSpaceOffs + nOffset; 769 } 770 if( bPaintSpace && nOldWidth > nSpaceOffs ) 771 { 772 SwTxtPaintInfo aInf( rInf ); 773 static sal_Char __READONLY_DATA sDoubleSpace[] = " "; 774 aInf.X( aInf.X() + nSpaceOffs ); 775 776 // --> FME 2005-08-12 #i53199# Adjust position of underline: 777 if ( rInf.GetUnderFnt() ) 778 { 779 const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() ); 780 rInf.GetUnderFnt()->SetPos( aNewPos ); 781 } 782 // <-- 783 784 pThis->Width( nOldWidth - nSpaceOffs + 12 ); 785 { 786 SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace ); 787 aInf.DrawText( *this, aInf.GetLen(), sal_True ); 788 } 789 } 790 pThis->Width( nOldWidth ); 791 } 792 } 793 } 794 795 796 /************************************************************************* 797 * class SwBulletPortion 798 *************************************************************************/ 799 800 // --> OD 2008-01-23 #newlistlevelattrs# 801 SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet, 802 const XubString& rBulletFollowedBy, 803 SwFont *pFont, 804 const sal_Bool bLft, 805 const sal_Bool bCntr, 806 const KSHORT nMinDst, 807 const bool bLabelAlignmentPosAndSpaceModeActive ) 808 : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) , 809 pFont, bLft, bCntr, nMinDst, 810 bLabelAlignmentPosAndSpaceModeActive ) 811 // <-- 812 { 813 SetWhichPor( POR_BULLET ); 814 } 815 816 /************************************************************************* 817 * class SwGrfNumPortion 818 *************************************************************************/ 819 820 #define GRFNUM_SECURE 10 821 822 // --> OD 2008-01-23 #newlistlevelattrs# 823 SwGrfNumPortion::SwGrfNumPortion( 824 SwFrm*, 825 const XubString& rGraphicFollowedBy, 826 const SvxBrushItem* pGrfBrush, 827 const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize, 828 const sal_Bool bLft, const sal_Bool bCntr, const KSHORT nMinDst, 829 const bool bLabelAlignmentPosAndSpaceModeActive ) : 830 SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst, 831 bLabelAlignmentPosAndSpaceModeActive ), 832 // <-- 833 pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 ) 834 { 835 SetWhichPor( POR_GRFNUM ); 836 SetAnimated( sal_False ); 837 bReplace = sal_False; 838 if( pGrfBrush ) 839 { 840 *pBrush = *pGrfBrush; 841 const Graphic* pGraph = pGrfBrush->GetGraphic(); 842 if( pGraph ) 843 SetAnimated( pGraph->IsAnimated() ); 844 else 845 bReplace = sal_True; 846 } 847 if( pGrfOrient ) 848 { 849 nYPos = pGrfOrient->GetPos(); 850 eOrient = pGrfOrient->GetVertOrient(); 851 } 852 else 853 { 854 nYPos = 0; 855 eOrient = text::VertOrientation::TOP; 856 } 857 Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) ); 858 nFixWidth = Width(); 859 nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE; 860 Height( KSHORT(nGrfHeight) ); 861 bNoPaint = sal_False; 862 } 863 864 SwGrfNumPortion::~SwGrfNumPortion() 865 { 866 if ( IsAnimated() ) 867 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId ); 868 delete pBrush; 869 } 870 871 void SwGrfNumPortion::StopAnimation( OutputDevice* pOut ) 872 { 873 if ( IsAnimated() ) 874 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId ); 875 } 876 877 sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf ) 878 { 879 SetHide( sal_False ); 880 // --> OD 2008-01-29 #newlistlevelattrs# 881 // Width( nFixWidth ); 882 KSHORT nFollowedByWidth( 0 ); 883 if ( mbLabelAlignmentPosAndSpaceModeActive ) 884 { 885 SwFldPortion::Format( rInf ); 886 nFollowedByWidth = Width(); 887 SetLen( 0 ); 888 } 889 Width( nFixWidth + nFollowedByWidth ); 890 // <-- 891 const sal_Bool bFull = rInf.Width() < rInf.X() + Width(); 892 const sal_Bool bFly = rInf.GetFly() || 893 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() ); 894 SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) ); 895 if( GetAscent() > Height() ) 896 Height( GetAscent() ); 897 898 if( bFull ) 899 { 900 Width( rInf.Width() - (KSHORT)rInf.X() ); 901 if( bFly ) 902 { 903 SetLen( 0 ); 904 SetNoPaint( sal_True ); 905 rInf.SetNumDone( sal_False ); 906 return sal_True; 907 } 908 } 909 rInf.SetNumDone( sal_True ); 910 // --> OD 2008-01-23 #newlistlevelattrs# 911 // long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 912 long nDiff = mbLabelAlignmentPosAndSpaceModeActive 913 ? 0 914 : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 915 // <-- 916 // Ein Vorschlag von Juergen und Volkmar: 917 // Der Textteil hinter der Numerierung sollte immer 918 // mindestens beim linken Rand beginnen. 919 if( nDiff < 0 ) 920 nDiff = 0; 921 else if ( nDiff > rInf.X() ) 922 nDiff -= rInf.X(); 923 if( nDiff < nFixWidth + nMinDist ) 924 nDiff = nFixWidth + nMinDist; 925 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde 926 // fieser Sonderfall: FlyFrm liegt in dem Bereich, 927 // den wir uns gerade unter den Nagel reissen wollen. 928 // Die NumberPortion wird als verborgen markiert. 929 if( nDiff > rInf.Width() ) 930 { 931 nDiff = rInf.Width(); 932 if( bFly ) 933 SetHide( sal_True ); 934 } 935 936 if( Width() < nDiff ) 937 Width( KSHORT(nDiff) ); 938 return bFull; 939 } 940 941 void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const 942 { 943 if( DontPaint() ) 944 return; 945 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt 946 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile. 947 */ 948 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() ) 949 { 950 SwLinePortion *pTmp = GetPortion(); 951 while ( pTmp && !pTmp->InTxtGrp() ) 952 pTmp = pTmp->GetPortion(); 953 if ( !pTmp ) 954 return; 955 } 956 Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE ); 957 long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) ); 958 Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE ); 959 960 // --> OD 2008-02-05 #newlistlevelattrs# 961 const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive || 962 ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) || 963 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ); 964 // <-- 965 966 if( nFixWidth < Width() && !bTmpLeft ) 967 { 968 KSHORT nOffset = Width() - nFixWidth; 969 if( nOffset < nMinDist ) 970 nOffset = 0; 971 else 972 { 973 if( IsCenter() ) 974 { 975 nOffset /= 2; 976 if( nOffset < nMinDist ) 977 nOffset = Width() - nFixWidth - nMinDist; 978 } 979 else 980 nOffset = nOffset - nMinDist; 981 } 982 aPos.X() += nOffset; 983 } 984 985 if( bReplace ) 986 { 987 KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120; 988 aSize = Size( nTmpH, nTmpH ); 989 aPos.Y() = rInf.Y() - nTmpH; 990 } 991 SwRect aTmp( aPos, aSize ); 992 993 sal_Bool bDraw = sal_True; 994 995 if ( IsAnimated() ) 996 { 997 bDraw = !rInf.GetOpt().IsGraphic(); 998 if( !nId ) 999 { 1000 SetId( long( rInf.GetTxtFrm() ) ); 1001 rInf.GetTxtFrm()->SetAnimation(); 1002 } 1003 if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw ) 1004 { 1005 rInf.NoteAnimation(); 1006 const ViewShell* pViewShell = rInf.GetVsh(); 1007 1008 // virtual device, not pdf export 1009 if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() && 1010 pViewShell && pViewShell->GetWin() ) 1011 { 1012 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId); 1013 rInf.GetTxtFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp ); 1014 } 1015 1016 1017 else if ( pViewShell && 1018 !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() && 1019 !pViewShell->IsPreView() && 1020 // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export. 1021 pViewShell->GetWin() ) 1022 // <-- 1023 { 1024 ( (Graphic*) pBrush->GetGraphic() )->StartAnimation( 1025 (OutputDevice*)rInf.GetOut(), aPos, aSize, nId ); 1026 } 1027 1028 // pdf export, printing, preview, stop animations... 1029 else 1030 bDraw = sal_True; 1031 } 1032 if( bDraw ) 1033 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId ); 1034 } 1035 1036 SwRect aRepaint( rInf.GetPaintRect() ); 1037 const SwTxtFrm& rFrm = *rInf.GetTxtFrm(); 1038 if( rFrm.IsVertical() ) 1039 { 1040 rFrm.SwitchHorizontalToVertical( aTmp ); 1041 rFrm.SwitchHorizontalToVertical( aRepaint ); 1042 } 1043 1044 if( rFrm.IsRightToLeft() ) 1045 { 1046 rFrm.SwitchLTRtoRTL( aTmp ); 1047 rFrm.SwitchLTRtoRTL( aRepaint ); 1048 } 1049 1050 if( bDraw && aTmp.HasArea() ) 1051 DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(), 1052 aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES ); 1053 } 1054 1055 void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent, 1056 long nFlyAsc, long nFlyDesc ) 1057 { 1058 if ( GetOrient() != text::VertOrientation::NONE ) 1059 { 1060 SetRelPos( 0 ); 1061 if ( GetOrient() == text::VertOrientation::CENTER ) 1062 SetRelPos( GetGrfHeight() / 2 ); 1063 else if ( GetOrient() == text::VertOrientation::TOP ) 1064 SetRelPos( GetGrfHeight() - GRFNUM_SECURE ); 1065 else if ( GetOrient() == text::VertOrientation::BOTTOM ) 1066 ; 1067 else if ( GetOrient() == text::VertOrientation::CHAR_CENTER ) 1068 SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 ); 1069 else if ( GetOrient() == text::VertOrientation::CHAR_TOP ) 1070 SetRelPos( nLnAscent ); 1071 else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM ) 1072 SetRelPos( GetGrfHeight() - nLnDescent ); 1073 else 1074 { 1075 if( GetGrfHeight() >= nFlyAsc + nFlyDesc ) 1076 { 1077 // wenn ich genauso gross bin wie die Zeile, brauche ich mich 1078 // nicht an der Zeile nicht weiter ausrichten, ich lasse 1079 // dann auch den max. Ascent der Zeile unveraendert 1080 1081 SetRelPos( nFlyAsc ); 1082 } 1083 else if ( GetOrient() == text::VertOrientation::LINE_CENTER ) 1084 SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 ); 1085 else if ( GetOrient() == text::VertOrientation::LINE_TOP ) 1086 SetRelPos( nFlyAsc ); 1087 else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM ) 1088 SetRelPos( GetGrfHeight() - nFlyDesc ); 1089 } 1090 } 1091 } 1092 1093 void SwTxtFrm::StopAnimation( OutputDevice* pOut ) 1094 { 1095 ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" ); 1096 if( HasPara() ) 1097 { 1098 SwLineLayout *pLine = GetPara(); 1099 while( pLine ) 1100 { 1101 SwLinePortion *pPor = pLine->GetPortion(); 1102 while( pPor ) 1103 { 1104 if( pPor->IsGrfNumPortion() ) 1105 ((SwGrfNumPortion*)pPor)->StopAnimation( pOut ); 1106 // Die Numerierungsportion sitzt immer vor dem ersten Zeichen, 1107 // deshalb koennen wir abbrechen, sobald wir eine Portion mit 1108 // einer Laenge > 0 erreicht haben. 1109 pPor = pPor->GetLen() ? 0 : pPor->GetPortion(); 1110 } 1111 pLine = pLine->GetLen() ? 0 : pLine->GetNext(); 1112 } 1113 } 1114 } 1115 1116 /************************************************************************* 1117 * SwCombinedPortion::SwCombinedPortion(..) 1118 * initializes the script array and clears the width array 1119 *************************************************************************/ 1120 1121 SwCombinedPortion::SwCombinedPortion( const XubString &rTxt ) 1122 : SwFldPortion( rTxt ) 1123 { 1124 SetLen(1); 1125 SetWhichPor( POR_COMBINED ); 1126 if( aExpand.Len() > 6 ) 1127 aExpand.Erase( 6 ); 1128 // Initialization of the scripttype array, 1129 // the arrays of width and position are filled by the format function 1130 if( pBreakIt->GetBreakIter().is() ) 1131 { 1132 sal_uInt8 nScr = SW_SCRIPTS; 1133 for( sal_uInt16 i = 0; i < rTxt.Len(); ++i ) 1134 { 1135 sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i ); 1136 switch ( nScript ) { 1137 case i18n::ScriptType::LATIN : nScr = SW_LATIN; break; 1138 case i18n::ScriptType::ASIAN : nScr = SW_CJK; break; 1139 case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break; 1140 } 1141 aScrType[i] = nScr; 1142 } 1143 } 1144 else 1145 { 1146 for( sal_uInt16 i = 0; i < 6; aScrType[i++] = 0 ) 1147 ; // nothing 1148 } 1149 memset( &aWidth, 0, sizeof(aWidth) ); 1150 } 1151 1152 /************************************************************************* 1153 * SwCombinedPortion::Paint(..) 1154 *************************************************************************/ 1155 1156 void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const 1157 { 1158 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" ); 1159 if( Width() ) 1160 { 1161 rInf.DrawBackBrush( *this ); 1162 rInf.DrawViewOpt( *this, POR_FLD ); 1163 1164 // do we have to repaint a post it portion? 1165 if( rInf.OnWin() && pPortion && !pPortion->Width() ) 1166 pPortion->PrePaint( rInf, this ); 1167 1168 sal_uInt16 nCount = aExpand.Len(); 1169 if( !nCount ) 1170 return; 1171 ASSERT( nCount < 7, "Too much combined characters" ); 1172 1173 // the first character of the second row 1174 sal_uInt16 nTop = ( nCount + 1 ) / 2; 1175 1176 SwFont aTmpFont( *rInf.GetFont() ); 1177 aTmpFont.SetProportion( nProportion ); // a smaller font 1178 SwFontSave aFontSave( rInf, &aTmpFont ); 1179 1180 sal_uInt16 i = 0; 1181 Point aOldPos = rInf.GetPos(); 1182 Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row 1183 while( i < nCount ) 1184 { 1185 if( i == nTop ) // change the row 1186 aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row 1187 aOutPos.X() = aOldPos.X() + aPos[i]; // X position 1188 const sal_uInt8 nAct = aScrType[i]; // script type 1189 aTmpFont.SetActual( nAct ); 1190 // if there're more than 4 characters to display, we choose fonts 1191 // with 2/3 of the original font width. 1192 if( aWidth[ nAct ] ) 1193 { 1194 Size aTmpSz = aTmpFont.GetSize( nAct ); 1195 if( aTmpSz.Width() != aWidth[ nAct ] ) 1196 { 1197 aTmpSz.Width() = aWidth[ nAct ]; 1198 aTmpFont.SetSize( aTmpSz, nAct ); 1199 } 1200 } 1201 ((SwTxtPaintInfo&)rInf).SetPos( aOutPos ); 1202 rInf.DrawText( aExpand, *this, i, 1 ); 1203 ++i; 1204 } 1205 // rInf is const, so we have to take back our manipulations 1206 ((SwTxtPaintInfo&)rInf).SetPos( aOldPos ); 1207 } 1208 } 1209 1210 /************************************************************************* 1211 * SwCombinedPortion::Format(..) 1212 *************************************************************************/ 1213 1214 sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf ) 1215 { 1216 sal_uInt16 nCount = aExpand.Len(); 1217 if( !nCount ) 1218 { 1219 Width( 0 ); 1220 return sal_False; 1221 } 1222 1223 ASSERT( nCount < 7, "Too much combined characters" ); 1224 // If there are leading "weak"-scripttyped characters in this portion, 1225 // they get the actual scripttype. 1226 sal_uInt16 i = 0; 1227 while( i < nCount && SW_SCRIPTS == aScrType[i] ) 1228 aScrType[i++] = rInf.GetFont()->GetActual(); 1229 if( nCount > 4 ) 1230 { 1231 // more than four? Ok, then we need the 2/3 font width 1232 i = 0; 1233 while( i < aExpand.Len() ) 1234 { 1235 ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" ); 1236 if( !aWidth[ aScrType[i] ] ) 1237 { 1238 rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) ); 1239 aWidth[ aScrType[i] ] = 1240 static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3); 1241 } 1242 ++i; 1243 } 1244 } 1245 1246 sal_uInt16 nTop = ( nCount + 1 ) / 2; // the first character of the second line 1247 ViewShell *pSh = rInf.GetTxtFrm()->getRootFrm()->GetCurrShell(); 1248 SwFont aTmpFont( *rInf.GetFont() ); 1249 SwFontSave aFontSave( rInf, &aTmpFont ); 1250 nProportion = 55; 1251 // In nMainAscent/Descent we store the ascent and descent 1252 // of the original surrounding font 1253 sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth; 1254 sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() ); 1255 const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() ); 1256 nMainDescent = nMainDescent - nMainAscent; 1257 // we start with a 50% font, but if we notice that the combined portion 1258 // becomes bigger than the surrounding font, we check 45% and maybe 40%. 1259 do 1260 { 1261 nProportion -= 5; 1262 aTmpFont.SetProportion( nProportion ); 1263 i = 0; 1264 memset( &aPos, 0, sizeof(aPos) ); 1265 nMaxDescent = 0; 1266 nMaxAscent = 0; 1267 nMaxWidth = 0; 1268 nUpPos = nLowPos = 0; 1269 1270 // Now we get the width of all characters. 1271 // The ascent and the width of the first line are stored in the 1272 // ascent member of the portion, the descent in nLowPos. 1273 // The ascent, descent and width of the second line are stored in the 1274 // local nMaxAscent, nMaxDescent and nMaxWidth variables. 1275 while( i < nCount ) 1276 { 1277 sal_uInt8 nScrp = aScrType[i]; 1278 aTmpFont.SetActual( nScrp ); 1279 if( aWidth[ nScrp ] ) 1280 { 1281 Size aFontSize( aTmpFont.GetSize( nScrp ) ); 1282 aFontSize.Width() = aWidth[ nScrp ]; 1283 aTmpFont.SetSize( aFontSize, nScrp ); 1284 } 1285 1286 SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 ); 1287 Size aSize = aTmpFont._GetTxtSize( aDrawInf ); 1288 sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() ); 1289 aPos[ i ] = (sal_uInt16)aSize.Width(); 1290 if( i == nTop ) // enter the second line 1291 { 1292 nLowPos = nMaxDescent; 1293 Height( nMaxDescent + nMaxAscent ); 1294 Width( nMaxWidth ); 1295 SetAscent( nMaxAscent ); 1296 nMaxAscent = 0; 1297 nMaxDescent = 0; 1298 nMaxWidth = 0; 1299 } 1300 nMaxWidth = nMaxWidth + aPos[ i++ ]; 1301 if( nAsc > nMaxAscent ) 1302 nMaxAscent = nAsc; 1303 if( aSize.Height() - nAsc > nMaxDescent ) 1304 nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc); 1305 } 1306 // for one or two characters we double the width of the portion 1307 if( nCount < 3 ) 1308 { 1309 nMaxWidth *= 2; 1310 Width( 2*Width() ); 1311 if( nCount < 2 ) 1312 { 1313 Height( nMaxAscent + nMaxDescent ); 1314 nLowPos = nMaxDescent; 1315 } 1316 } 1317 Height( Height() + nMaxDescent + nMaxAscent ); 1318 nUpPos = nMaxAscent; 1319 SetAscent( Height() - nMaxDescent - nLowPos ); 1320 } while( nProportion > 40 && ( GetAscent() > nMainAscent || 1321 Height() - GetAscent() > nMainDescent ) ); 1322 // if the combined portion is smaller than the surrounding text, 1323 // the portion grows. This looks better, if there's a character background. 1324 if( GetAscent() < nMainAscent ) 1325 { 1326 Height( Height() + nMainAscent - GetAscent() ); 1327 SetAscent( nMainAscent ); 1328 } 1329 if( Height() < nMainAscent + nMainDescent ) 1330 Height( nMainAscent + nMainDescent ); 1331 1332 // We calculate the x positions of the characters in both lines.. 1333 sal_uInt16 nTopDiff = 0; 1334 sal_uInt16 nBotDiff = 0; 1335 if( nMaxWidth > Width() ) 1336 { 1337 nTopDiff = ( nMaxWidth - Width() ) / 2; 1338 Width( nMaxWidth ); 1339 } 1340 else 1341 nBotDiff = ( Width() - nMaxWidth ) / 2; 1342 switch( nTop) 1343 { 1344 case 3: aPos[1] = aPos[0] + nTopDiff; // no break 1345 case 2: aPos[nTop-1] = Width() - aPos[nTop-1]; 1346 } 1347 aPos[0] = 0; 1348 switch( nCount ) 1349 { 1350 case 5: aPos[4] = aPos[3] + nBotDiff; // no break 1351 case 3: aPos[nTop] = nBotDiff; break; 1352 case 6: aPos[4] = aPos[3] + nBotDiff; // no break 1353 case 4: aPos[nTop] = 0; // no break 1354 case 2: aPos[nCount-1] = Width() - aPos[nCount-1]; 1355 } 1356 1357 // Does the combined portion fit the line? 1358 const sal_Bool bFull = rInf.Width() < rInf.X() + Width(); 1359 if( bFull ) 1360 { 1361 if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp() 1362 || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) ) 1363 Width( (sal_uInt16)( rInf.Width() - rInf.X() ) ); 1364 else 1365 { 1366 Truncate(); 1367 Width( 0 ); 1368 SetLen( 0 ); 1369 if( rInf.GetLast() ) 1370 rInf.GetLast()->FormatEOL( rInf ); 1371 } 1372 } 1373 return bFull; 1374 } 1375 1376 /************************************************************************* 1377 * SwCombinedPortion::GetViewWidth(..) 1378 *************************************************************************/ 1379 1380 KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const 1381 { 1382 if( !GetLen() ) // for the dummy part at the end of the line, where 1383 return 0; // the combined portion doesn't fit. 1384 return SwFldPortion::GetViewWidth( rInf ); 1385 } 1386