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