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