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 SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder ); 72 pClone->SetNextOffset( nNextOffset ); 73 pClone->m_bNoLength = this->m_bNoLength; 74 return pClone; 75 } 76 77 void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld ) 78 { 79 ASSERT( pFld, "TakeNextOffset: Missing Source" ); 80 nNextOffset = pFld->GetNextOffset(); 81 aExpand.Erase( 0, nNextOffset ); 82 bFollow = sal_True; 83 } 84 85 SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold ) 86 : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0), 87 bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold ) 88 , m_bNoLength( sal_False ) 89 { 90 SetWhichPor( POR_FLD ); 91 //IAccessibility2 Implementation 2009----- 92 m_nAttrFldType = 0; 93 //-----IAccessibility2 Implementation 2009 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 case CHAR_ZWSP : 398 case CHAR_ZWNBSP : 399 case CH_TXTATR_BREAKWORD: 400 case CH_TXTATR_INWORD: 401 { 402 aNew.Erase( 0, 1 ); 403 ++nNextOfst; 404 break; 405 } 406 default: ; 407 } 408 409 // Even if there is no more text left for a follow field, 410 // we have to build a follow field portion (without font), 411 // otherwise the HookChar mechanism would not work. 412 SwFldPortion *pFld = Clone( aNew ); 413 if( aNew.Len() && !pFld->GetFont() ) 414 { 415 SwFont *pNewFnt = new SwFont( *rInf.GetFont() ); 416 pFld->SetFont( pNewFnt ); 417 } 418 pFld->SetFollow( sal_True ); 419 SetHasFollow( sal_True ); 420 // In nNextOffset steht bei einem neuangelegten Feld zunaechst 421 // der Offset, an dem es selbst im Originalstring beginnt. 422 // Wenn beim Formatieren ein FollowFeld angelegt wird, wird 423 // der Offset dieses FollowFelds in nNextOffset festgehalten. 424 nNextOffset = nNextOffset + nNextOfst; 425 pFld->SetNextOffset( nNextOffset ); 426 rInf.SetRest( pFld ); 427 } 428 } 429 430 if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() ) 431 rInf.GetLast()->FormatEOL( rInf ); 432 return bFull; 433 } 434 435 /************************************************************************* 436 * virtual SwFldPortion::Paint() 437 *************************************************************************/ 438 439 void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const 440 { 441 SwFontSave aSave( rInf, pFnt ); 442 443 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" ); 444 if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) ) 445 { 446 // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ... 447 rInf.DrawViewOpt( *this, POR_FLD ); 448 SwExpandPortion::Paint( rInf ); 449 } 450 } 451 452 /************************************************************************* 453 * virtual SwFldPortion::GetExpTxt() 454 *************************************************************************/ 455 456 sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 457 { 458 rTxt = aExpand; 459 if( !rTxt.Len() && rInf.OnWin() && 460 !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && 461 SwViewOption::IsFieldShadings() && 462 !HasFollow() ) 463 rTxt = ' '; 464 return sal_True; 465 } 466 467 /************************************************************************* 468 * virtual SwFldPortion::HandlePortion() 469 *************************************************************************/ 470 471 void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const 472 { 473 rPH.Special( GetLen(), aExpand, GetWhichPor() ); 474 //IAccessibility2 Implementation 2009----- 475 if( GetWhichPor() == POR_FLD ) 476 { 477 rPH.SetAttrFieldType(m_nAttrFldType); 478 } 479 //-----IAccessibility2 Implementation 2009 480 } 481 482 /************************************************************************* 483 * virtual SwFldPortion::GetTxtSize() 484 *************************************************************************/ 485 486 SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 487 { 488 SwFontSave aSave( rInf, pFnt ); 489 SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) ); 490 return aSize; 491 } 492 493 /************************************************************************* 494 * class SwHiddenPortion 495 *************************************************************************/ 496 497 SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const 498 { 499 SwFont *pNewFnt; 500 if( 0 != ( pNewFnt = pFnt ) ) 501 pNewFnt = new SwFont( *pFnt ); 502 return new SwHiddenPortion( rExpand, pNewFnt ); 503 } 504 505 /************************************************************************* 506 * virtual SwHiddenPortion::Paint() 507 *************************************************************************/ 508 509 void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const 510 { 511 if( Width() ) 512 { 513 SwFontSave aSave( rInf, pFnt ); 514 rInf.DrawViewOpt( *this, POR_HIDDEN ); 515 SwExpandPortion::Paint( rInf ); 516 } 517 } 518 519 /************************************************************************* 520 * virtual SwHiddenPortion::GetExpTxt() 521 *************************************************************************/ 522 523 sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 524 { 525 // Nicht auf IsHidden() abfragen ! 526 return SwFldPortion::GetExpTxt( rInf, rTxt ); 527 } 528 529 /************************************************************************* 530 * class SwNumberPortion 531 *************************************************************************/ 532 533 // --> OD 2008-01-23 #newlistlevelattrs# 534 SwNumberPortion::SwNumberPortion( const XubString &rExpand, 535 SwFont *pFont, 536 const sal_Bool bLft, 537 const sal_Bool bCntr, 538 const KSHORT nMinDst, 539 const bool bLabelAlignmentPosAndSpaceModeActive ) 540 : SwFldPortion( rExpand, pFont ), 541 nFixWidth(0), 542 nMinDist( nMinDst ), 543 // --> OD 2008-01-23 #newlistlevelattrs# 544 mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive ) 545 // <-- 546 { 547 SetWhichPor( POR_NUMBER ); 548 SetLeft( bLft ); 549 SetHide( sal_False ); 550 SetCenter( bCntr ); 551 } 552 553 xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const 554 { 555 return 0; 556 } 557 558 SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const 559 { 560 SwFont *pNewFnt; 561 if( 0 != ( pNewFnt = pFnt ) ) 562 pNewFnt = new SwFont( *pFnt ); 563 // --> OD 2008-01-23 #newlistlevelattrs# 564 return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(), 565 nMinDist, mbLabelAlignmentPosAndSpaceModeActive ); 566 // <-- 567 } 568 569 /************************************************************************* 570 * virtual SwNumberPortion::Format() 571 *************************************************************************/ 572 573 // 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen! 574 // 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text 575 // eingibt, bis die Zeile ueberlaeuft. 576 // Man muss die Fly-Ausweichmanoever beachten! 577 578 sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf ) 579 { 580 SetHide( sal_False ); 581 const sal_Bool bFull = SwFldPortion::Format( rInf ); 582 SetLen( 0 ); 583 // a numbering portion can be contained in a rotated portion!!! 584 nFixWidth = rInf.IsMulti() ? Height() : Width(); 585 rInf.SetNumDone( !rInf.GetRest() ); 586 if( rInf.IsNumDone() ) 587 { 588 // SetAscent( rInf.GetAscent() ); 589 ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" ); 590 591 long nDiff( 0 ); 592 // --> OD 2008-01-23 #newlistlevelattrs# 593 if ( !mbLabelAlignmentPosAndSpaceModeActive ) 594 { 595 if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) && 596 // --> FME 2004-08-13 #i32902# 597 !IsFtnNumPortion() ) 598 // <-- 599 { 600 nDiff = rInf.Left() 601 + rInf.GetTxtFrm()->GetTxtNode()-> 602 GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst() 603 - rInf.First() 604 + rInf.ForcedLeftMargin(); 605 } 606 else 607 { 608 nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 609 } 610 } 611 // <-- 612 // Ein Vorschlag von Juergen und Volkmar: 613 // Der Textteil hinter der Numerierung sollte immer 614 // mindestens beim linken Rand beginnen. 615 if( nDiff < 0 ) 616 nDiff = 0; 617 else if ( nDiff > rInf.X() ) 618 nDiff -= rInf.X(); 619 else 620 nDiff = 0; 621 622 if( nDiff < nFixWidth + nMinDist ) 623 nDiff = nFixWidth + nMinDist; 624 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde 625 // fieser Sonderfall: FlyFrm liegt in dem Bereich, 626 // den wir uns gerade unter den Nagel reissen wollen. 627 // Die NumberPortion wird als verborgen markiert. 628 const sal_Bool bFly = rInf.GetFly() || 629 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() ); 630 if( nDiff > rInf.Width() ) 631 { 632 nDiff = rInf.Width(); 633 if ( bFly ) 634 SetHide( sal_True ); 635 } 636 637 // A numbering portion can be inside a SwRotatedPortion. Then the 638 // Height has to be changed 639 if ( rInf.IsMulti() ) 640 { 641 if ( Height() < nDiff ) 642 Height( KSHORT( nDiff ) ); 643 } 644 else if( Width() < nDiff ) 645 Width( KSHORT(nDiff) ); 646 } 647 return bFull; 648 } 649 650 void SwNumberPortion::FormatEOL( SwTxtFormatInfo& ) 651 { 652 /* Ein FormatEOL deutet daraufhin, dass der folgende Text 653 * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert, 654 * wird diese NumberPortion verborgen. 655 */ 656 657 // This caused trouble with flys anchored as characters. 658 // If one of these is numbered but does not fit to the line, 659 // it calls this function, causing a loop because both the number 660 // portion and the fly portion go to the next line 661 // SetHide( sal_True ); 662 } 663 664 /************************************************************************* 665 * virtual SwNumberPortion::Paint() 666 *************************************************************************/ 667 668 void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const 669 { 670 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt 671 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile. 672 */ 673 674 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() ) 675 { 676 SwLinePortion *pTmp = GetPortion(); 677 while ( pTmp && !pTmp->InTxtGrp() ) 678 pTmp = pTmp->GetPortion(); 679 if ( !pTmp ) 680 return; 681 } 682 683 // calculate the width of the number portion, including follows 684 const KSHORT nOldWidth = Width(); 685 sal_uInt16 nSumWidth = 0; 686 sal_uInt16 nOffset = 0; 687 688 const SwLinePortion* pTmp = this; 689 while ( pTmp && pTmp->InNumberGrp() ) 690 { 691 nSumWidth = nSumWidth + pTmp->Width(); 692 if ( ((SwNumberPortion*)pTmp)->HasFollow() ) 693 pTmp = pTmp->GetPortion(); 694 else 695 { 696 nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth; 697 break; 698 } 699 } 700 701 // The master portion takes care for painting the background of the 702 // follow field portions 703 if ( ! IsFollow() ) 704 { 705 SwLinePortion *pThis = (SwLinePortion*)this; 706 pThis->Width( nSumWidth ); 707 rInf.DrawViewOpt( *this, POR_NUMBER ); 708 pThis->Width( nOldWidth ); 709 } 710 711 if( aExpand.Len() ) 712 { 713 const SwFont *pTmpFnt = rInf.GetFont(); 714 sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() || 715 UNDERLINE_NONE != pTmpFnt->GetOverline() || 716 STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) && 717 !pTmpFnt->IsWordLineMode(); 718 if( bPaintSpace && pFnt ) 719 bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() || 720 UNDERLINE_NONE != pFnt->GetOverline() || 721 STRIKEOUT_NONE != pFnt->GetStrikeout() ) && 722 !pFnt->IsWordLineMode(); 723 724 SwFontSave aSave( rInf, pFnt ); 725 726 if( nFixWidth == Width() && ! HasFollow() ) 727 SwExpandPortion::Paint( rInf ); 728 else 729 { 730 // logisches const: Width wird wieder zurueckgesetzt 731 SwLinePortion *pThis = (SwLinePortion*)this; 732 bPaintSpace = bPaintSpace && nFixWidth < nOldWidth; 733 KSHORT nSpaceOffs = nFixWidth; 734 pThis->Width( nFixWidth ); 735 736 if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) || 737 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) ) 738 SwExpandPortion::Paint( rInf ); 739 else 740 { 741 SwTxtPaintInfo aInf( rInf ); 742 if( nOffset < nMinDist ) 743 nOffset = 0; 744 else 745 { 746 if( IsCenter() ) 747 { 748 /* #110778# a / 2 * 2 == a is not a tautology */ 749 KSHORT nTmpOffset = nOffset; 750 nOffset /= 2; 751 if( nOffset < nMinDist ) 752 nOffset = nTmpOffset - nMinDist; 753 } 754 else 755 nOffset = nOffset - nMinDist; 756 } 757 aInf.X( aInf.X() + nOffset ); 758 SwExpandPortion::Paint( aInf ); 759 if( bPaintSpace ) 760 nSpaceOffs = nSpaceOffs + nOffset; 761 } 762 if( bPaintSpace && nOldWidth > nSpaceOffs ) 763 { 764 SwTxtPaintInfo aInf( rInf ); 765 static sal_Char __READONLY_DATA sDoubleSpace[] = " "; 766 aInf.X( aInf.X() + nSpaceOffs ); 767 768 // --> FME 2005-08-12 #i53199# Adjust position of underline: 769 if ( rInf.GetUnderFnt() ) 770 { 771 const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() ); 772 rInf.GetUnderFnt()->SetPos( aNewPos ); 773 } 774 // <-- 775 776 pThis->Width( nOldWidth - nSpaceOffs + 12 ); 777 { 778 SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace ); 779 aInf.DrawText( *this, aInf.GetLen(), sal_True ); 780 } 781 } 782 pThis->Width( nOldWidth ); 783 } 784 } 785 } 786 787 788 /************************************************************************* 789 * class SwBulletPortion 790 *************************************************************************/ 791 792 // --> OD 2008-01-23 #newlistlevelattrs# 793 SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet, 794 const XubString& rBulletFollowedBy, 795 SwFont *pFont, 796 const sal_Bool bLft, 797 const sal_Bool bCntr, 798 const KSHORT nMinDst, 799 const bool bLabelAlignmentPosAndSpaceModeActive ) 800 : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) , 801 pFont, bLft, bCntr, nMinDst, 802 bLabelAlignmentPosAndSpaceModeActive ) 803 // <-- 804 { 805 SetWhichPor( POR_BULLET ); 806 } 807 808 /************************************************************************* 809 * class SwGrfNumPortion 810 *************************************************************************/ 811 812 #define GRFNUM_SECURE 10 813 814 // --> OD 2008-01-23 #newlistlevelattrs# 815 SwGrfNumPortion::SwGrfNumPortion( 816 SwFrm*, 817 const XubString& rGraphicFollowedBy, 818 const SvxBrushItem* pGrfBrush, 819 const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize, 820 const sal_Bool bLft, const sal_Bool bCntr, const KSHORT nMinDst, 821 const bool bLabelAlignmentPosAndSpaceModeActive ) : 822 SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst, 823 bLabelAlignmentPosAndSpaceModeActive ), 824 // <-- 825 pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 ) 826 { 827 SetWhichPor( POR_GRFNUM ); 828 SetAnimated( sal_False ); 829 bReplace = sal_False; 830 if( pGrfBrush ) 831 { 832 *pBrush = *pGrfBrush; 833 const Graphic* pGraph = pGrfBrush->GetGraphic(); 834 if( pGraph ) 835 SetAnimated( pGraph->IsAnimated() ); 836 else 837 bReplace = sal_True; 838 } 839 if( pGrfOrient ) 840 { 841 nYPos = pGrfOrient->GetPos(); 842 eOrient = pGrfOrient->GetVertOrient(); 843 } 844 else 845 { 846 nYPos = 0; 847 eOrient = text::VertOrientation::TOP; 848 } 849 Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) ); 850 nFixWidth = Width(); 851 nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE; 852 Height( KSHORT(nGrfHeight) ); 853 bNoPaint = sal_False; 854 } 855 856 SwGrfNumPortion::~SwGrfNumPortion() 857 { 858 if ( IsAnimated() ) 859 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId ); 860 delete pBrush; 861 } 862 863 void SwGrfNumPortion::StopAnimation( OutputDevice* pOut ) 864 { 865 if ( IsAnimated() ) 866 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId ); 867 } 868 869 sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf ) 870 { 871 SetHide( sal_False ); 872 // --> OD 2008-01-29 #newlistlevelattrs# 873 // Width( nFixWidth ); 874 KSHORT nFollowedByWidth( 0 ); 875 if ( mbLabelAlignmentPosAndSpaceModeActive ) 876 { 877 SwFldPortion::Format( rInf ); 878 nFollowedByWidth = Width(); 879 SetLen( 0 ); 880 } 881 Width( nFixWidth + nFollowedByWidth ); 882 // <-- 883 const sal_Bool bFull = rInf.Width() < rInf.X() + Width(); 884 const sal_Bool bFly = rInf.GetFly() || 885 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() ); 886 SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) ); 887 if( GetAscent() > Height() ) 888 Height( GetAscent() ); 889 890 if( bFull ) 891 { 892 Width( rInf.Width() - (KSHORT)rInf.X() ); 893 if( bFly ) 894 { 895 SetLen( 0 ); 896 SetNoPaint( sal_True ); 897 rInf.SetNumDone( sal_False ); 898 return sal_True; 899 } 900 } 901 rInf.SetNumDone( sal_True ); 902 // --> OD 2008-01-23 #newlistlevelattrs# 903 // long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 904 long nDiff = mbLabelAlignmentPosAndSpaceModeActive 905 ? 0 906 : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 907 // <-- 908 // Ein Vorschlag von Juergen und Volkmar: 909 // Der Textteil hinter der Numerierung sollte immer 910 // mindestens beim linken Rand beginnen. 911 if( nDiff < 0 ) 912 nDiff = 0; 913 else if ( nDiff > rInf.X() ) 914 nDiff -= rInf.X(); 915 if( nDiff < nFixWidth + nMinDist ) 916 nDiff = nFixWidth + nMinDist; 917 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde 918 // fieser Sonderfall: FlyFrm liegt in dem Bereich, 919 // den wir uns gerade unter den Nagel reissen wollen. 920 // Die NumberPortion wird als verborgen markiert. 921 if( nDiff > rInf.Width() ) 922 { 923 nDiff = rInf.Width(); 924 if( bFly ) 925 SetHide( sal_True ); 926 } 927 928 if( Width() < nDiff ) 929 Width( KSHORT(nDiff) ); 930 return bFull; 931 } 932 933 void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const 934 { 935 if( DontPaint() ) 936 return; 937 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt 938 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile. 939 */ 940 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() ) 941 { 942 SwLinePortion *pTmp = GetPortion(); 943 while ( pTmp && !pTmp->InTxtGrp() ) 944 pTmp = pTmp->GetPortion(); 945 if ( !pTmp ) 946 return; 947 } 948 Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE ); 949 long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) ); 950 Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE ); 951 952 // --> OD 2008-02-05 #newlistlevelattrs# 953 const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive || 954 ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) || 955 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ); 956 // <-- 957 958 if( nFixWidth < Width() && !bTmpLeft ) 959 { 960 KSHORT nOffset = Width() - nFixWidth; 961 if( nOffset < nMinDist ) 962 nOffset = 0; 963 else 964 { 965 if( IsCenter() ) 966 { 967 nOffset /= 2; 968 if( nOffset < nMinDist ) 969 nOffset = Width() - nFixWidth - nMinDist; 970 } 971 else 972 nOffset = nOffset - nMinDist; 973 } 974 aPos.X() += nOffset; 975 } 976 977 if( bReplace ) 978 { 979 KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120; 980 aSize = Size( nTmpH, nTmpH ); 981 aPos.Y() = rInf.Y() - nTmpH; 982 } 983 SwRect aTmp( aPos, aSize ); 984 985 sal_Bool bDraw = sal_True; 986 987 if ( IsAnimated() ) 988 { 989 bDraw = !rInf.GetOpt().IsGraphic(); 990 if( !nId ) 991 { 992 SetId( long( rInf.GetTxtFrm() ) ); 993 rInf.GetTxtFrm()->SetAnimation(); 994 } 995 if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw ) 996 { 997 rInf.NoteAnimation(); 998 const ViewShell* pViewShell = rInf.GetVsh(); 999 1000 // virtual device, not pdf export 1001 if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() && 1002 pViewShell && pViewShell->GetWin() ) 1003 { 1004 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId); 1005 rInf.GetTxtFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp ); 1006 } 1007 1008 1009 else if ( pViewShell && 1010 !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() && 1011 !pViewShell->IsPreView() && 1012 // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export. 1013 pViewShell->GetWin() ) 1014 // <-- 1015 { 1016 ( (Graphic*) pBrush->GetGraphic() )->StartAnimation( 1017 (OutputDevice*)rInf.GetOut(), aPos, aSize, nId ); 1018 } 1019 1020 // pdf export, printing, preview, stop animations... 1021 else 1022 bDraw = sal_True; 1023 } 1024 if( bDraw ) 1025 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId ); 1026 } 1027 1028 SwRect aRepaint( rInf.GetPaintRect() ); 1029 const SwTxtFrm& rFrm = *rInf.GetTxtFrm(); 1030 if( rFrm.IsVertical() ) 1031 { 1032 rFrm.SwitchHorizontalToVertical( aTmp ); 1033 rFrm.SwitchHorizontalToVertical( aRepaint ); 1034 } 1035 1036 if( rFrm.IsRightToLeft() ) 1037 { 1038 rFrm.SwitchLTRtoRTL( aTmp ); 1039 rFrm.SwitchLTRtoRTL( aRepaint ); 1040 } 1041 1042 if( bDraw && aTmp.HasArea() ) 1043 DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(), 1044 aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES ); 1045 } 1046 1047 void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent, 1048 long nFlyAsc, long nFlyDesc ) 1049 { 1050 if ( GetOrient() != text::VertOrientation::NONE ) 1051 { 1052 SetRelPos( 0 ); 1053 if ( GetOrient() == text::VertOrientation::CENTER ) 1054 SetRelPos( GetGrfHeight() / 2 ); 1055 else if ( GetOrient() == text::VertOrientation::TOP ) 1056 SetRelPos( GetGrfHeight() - GRFNUM_SECURE ); 1057 else if ( GetOrient() == text::VertOrientation::BOTTOM ) 1058 ; 1059 else if ( GetOrient() == text::VertOrientation::CHAR_CENTER ) 1060 SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 ); 1061 else if ( GetOrient() == text::VertOrientation::CHAR_TOP ) 1062 SetRelPos( nLnAscent ); 1063 else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM ) 1064 SetRelPos( GetGrfHeight() - nLnDescent ); 1065 else 1066 { 1067 if( GetGrfHeight() >= nFlyAsc + nFlyDesc ) 1068 { 1069 // wenn ich genauso gross bin wie die Zeile, brauche ich mich 1070 // nicht an der Zeile nicht weiter ausrichten, ich lasse 1071 // dann auch den max. Ascent der Zeile unveraendert 1072 1073 SetRelPos( nFlyAsc ); 1074 } 1075 else if ( GetOrient() == text::VertOrientation::LINE_CENTER ) 1076 SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 ); 1077 else if ( GetOrient() == text::VertOrientation::LINE_TOP ) 1078 SetRelPos( nFlyAsc ); 1079 else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM ) 1080 SetRelPos( GetGrfHeight() - nFlyDesc ); 1081 } 1082 } 1083 } 1084 1085 void SwTxtFrm::StopAnimation( OutputDevice* pOut ) 1086 { 1087 ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" ); 1088 if( HasPara() ) 1089 { 1090 SwLineLayout *pLine = GetPara(); 1091 while( pLine ) 1092 { 1093 SwLinePortion *pPor = pLine->GetPortion(); 1094 while( pPor ) 1095 { 1096 if( pPor->IsGrfNumPortion() ) 1097 ((SwGrfNumPortion*)pPor)->StopAnimation( pOut ); 1098 // Die Numerierungsportion sitzt immer vor dem ersten Zeichen, 1099 // deshalb koennen wir abbrechen, sobald wir eine Portion mit 1100 // einer Laenge > 0 erreicht haben. 1101 pPor = pPor->GetLen() ? 0 : pPor->GetPortion(); 1102 } 1103 pLine = pLine->GetLen() ? 0 : pLine->GetNext(); 1104 } 1105 } 1106 } 1107 1108 /************************************************************************* 1109 * SwCombinedPortion::SwCombinedPortion(..) 1110 * initializes the script array and clears the width array 1111 *************************************************************************/ 1112 1113 SwCombinedPortion::SwCombinedPortion( const XubString &rTxt ) 1114 : SwFldPortion( rTxt ) 1115 { 1116 SetLen(1); 1117 SetWhichPor( POR_COMBINED ); 1118 if( aExpand.Len() > 6 ) 1119 aExpand.Erase( 6 ); 1120 // Initialization of the scripttype array, 1121 // the arrays of width and position are filled by the format function 1122 if( pBreakIt->GetBreakIter().is() ) 1123 { 1124 sal_uInt8 nScr = SW_SCRIPTS; 1125 for( sal_uInt16 i = 0; i < rTxt.Len(); ++i ) 1126 { 1127 sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i ); 1128 switch ( nScript ) { 1129 case i18n::ScriptType::LATIN : nScr = SW_LATIN; break; 1130 case i18n::ScriptType::ASIAN : nScr = SW_CJK; break; 1131 case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break; 1132 } 1133 aScrType[i] = nScr; 1134 } 1135 } 1136 else 1137 { 1138 for( sal_uInt16 i = 0; i < 6; aScrType[i++] = 0 ) 1139 ; // nothing 1140 } 1141 memset( &aWidth, 0, sizeof(aWidth) ); 1142 } 1143 1144 /************************************************************************* 1145 * SwCombinedPortion::Paint(..) 1146 *************************************************************************/ 1147 1148 void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const 1149 { 1150 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" ); 1151 if( Width() ) 1152 { 1153 rInf.DrawBackBrush( *this ); 1154 rInf.DrawViewOpt( *this, POR_FLD ); 1155 1156 // do we have to repaint a post it portion? 1157 if( rInf.OnWin() && pPortion && !pPortion->Width() ) 1158 pPortion->PrePaint( rInf, this ); 1159 1160 sal_uInt16 nCount = aExpand.Len(); 1161 if( !nCount ) 1162 return; 1163 ASSERT( nCount < 7, "Too much combined characters" ); 1164 1165 // the first character of the second row 1166 sal_uInt16 nTop = ( nCount + 1 ) / 2; 1167 1168 SwFont aTmpFont( *rInf.GetFont() ); 1169 aTmpFont.SetProportion( nProportion ); // a smaller font 1170 SwFontSave aFontSave( rInf, &aTmpFont ); 1171 1172 sal_uInt16 i = 0; 1173 Point aOldPos = rInf.GetPos(); 1174 Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row 1175 while( i < nCount ) 1176 { 1177 if( i == nTop ) // change the row 1178 aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row 1179 aOutPos.X() = aOldPos.X() + aPos[i]; // X position 1180 const sal_uInt8 nAct = aScrType[i]; // script type 1181 aTmpFont.SetActual( nAct ); 1182 // if there're more than 4 characters to display, we choose fonts 1183 // with 2/3 of the original font width. 1184 if( aWidth[ nAct ] ) 1185 { 1186 Size aTmpSz = aTmpFont.GetSize( nAct ); 1187 if( aTmpSz.Width() != aWidth[ nAct ] ) 1188 { 1189 aTmpSz.Width() = aWidth[ nAct ]; 1190 aTmpFont.SetSize( aTmpSz, nAct ); 1191 } 1192 } 1193 ((SwTxtPaintInfo&)rInf).SetPos( aOutPos ); 1194 rInf.DrawText( aExpand, *this, i, 1 ); 1195 ++i; 1196 } 1197 // rInf is const, so we have to take back our manipulations 1198 ((SwTxtPaintInfo&)rInf).SetPos( aOldPos ); 1199 } 1200 } 1201 1202 /************************************************************************* 1203 * SwCombinedPortion::Format(..) 1204 *************************************************************************/ 1205 1206 sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf ) 1207 { 1208 sal_uInt16 nCount = aExpand.Len(); 1209 if( !nCount ) 1210 { 1211 Width( 0 ); 1212 return sal_False; 1213 } 1214 1215 ASSERT( nCount < 7, "Too much combined characters" ); 1216 // If there are leading "weak"-scripttyped characters in this portion, 1217 // they get the actual scripttype. 1218 sal_uInt16 i = 0; 1219 while( i < nCount && SW_SCRIPTS == aScrType[i] ) 1220 aScrType[i++] = rInf.GetFont()->GetActual(); 1221 if( nCount > 4 ) 1222 { 1223 // more than four? Ok, then we need the 2/3 font width 1224 i = 0; 1225 while( i < aExpand.Len() ) 1226 { 1227 ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" ); 1228 if( !aWidth[ aScrType[i] ] ) 1229 { 1230 rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) ); 1231 aWidth[ aScrType[i] ] = 1232 static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3); 1233 } 1234 ++i; 1235 } 1236 } 1237 1238 sal_uInt16 nTop = ( nCount + 1 ) / 2; // the first character of the second line 1239 ViewShell *pSh = rInf.GetTxtFrm()->getRootFrm()->GetCurrShell(); 1240 SwFont aTmpFont( *rInf.GetFont() ); 1241 SwFontSave aFontSave( rInf, &aTmpFont ); 1242 nProportion = 55; 1243 // In nMainAscent/Descent we store the ascent and descent 1244 // of the original surrounding font 1245 sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth; 1246 sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() ); 1247 const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() ); 1248 nMainDescent = nMainDescent - nMainAscent; 1249 // we start with a 50% font, but if we notice that the combined portion 1250 // becomes bigger than the surrounding font, we check 45% and maybe 40%. 1251 do 1252 { 1253 nProportion -= 5; 1254 aTmpFont.SetProportion( nProportion ); 1255 i = 0; 1256 memset( &aPos, 0, sizeof(aPos) ); 1257 nMaxDescent = 0; 1258 nMaxAscent = 0; 1259 nMaxWidth = 0; 1260 nUpPos = nLowPos = 0; 1261 1262 // Now we get the width of all characters. 1263 // The ascent and the width of the first line are stored in the 1264 // ascent member of the portion, the descent in nLowPos. 1265 // The ascent, descent and width of the second line are stored in the 1266 // local nMaxAscent, nMaxDescent and nMaxWidth variables. 1267 while( i < nCount ) 1268 { 1269 sal_uInt8 nScrp = aScrType[i]; 1270 aTmpFont.SetActual( nScrp ); 1271 if( aWidth[ nScrp ] ) 1272 { 1273 Size aFontSize( aTmpFont.GetSize( nScrp ) ); 1274 aFontSize.Width() = aWidth[ nScrp ]; 1275 aTmpFont.SetSize( aFontSize, nScrp ); 1276 } 1277 1278 SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 ); 1279 Size aSize = aTmpFont._GetTxtSize( aDrawInf ); 1280 sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() ); 1281 aPos[ i ] = (sal_uInt16)aSize.Width(); 1282 if( i == nTop ) // enter the second line 1283 { 1284 nLowPos = nMaxDescent; 1285 Height( nMaxDescent + nMaxAscent ); 1286 Width( nMaxWidth ); 1287 SetAscent( nMaxAscent ); 1288 nMaxAscent = 0; 1289 nMaxDescent = 0; 1290 nMaxWidth = 0; 1291 } 1292 nMaxWidth = nMaxWidth + aPos[ i++ ]; 1293 if( nAsc > nMaxAscent ) 1294 nMaxAscent = nAsc; 1295 if( aSize.Height() - nAsc > nMaxDescent ) 1296 nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc); 1297 } 1298 // for one or two characters we double the width of the portion 1299 if( nCount < 3 ) 1300 { 1301 nMaxWidth *= 2; 1302 Width( 2*Width() ); 1303 if( nCount < 2 ) 1304 { 1305 Height( nMaxAscent + nMaxDescent ); 1306 nLowPos = nMaxDescent; 1307 } 1308 } 1309 Height( Height() + nMaxDescent + nMaxAscent ); 1310 nUpPos = nMaxAscent; 1311 SetAscent( Height() - nMaxDescent - nLowPos ); 1312 } while( nProportion > 40 && ( GetAscent() > nMainAscent || 1313 Height() - GetAscent() > nMainDescent ) ); 1314 // if the combined portion is smaller than the surrounding text, 1315 // the portion grows. This looks better, if there's a character background. 1316 if( GetAscent() < nMainAscent ) 1317 { 1318 Height( Height() + nMainAscent - GetAscent() ); 1319 SetAscent( nMainAscent ); 1320 } 1321 if( Height() < nMainAscent + nMainDescent ) 1322 Height( nMainAscent + nMainDescent ); 1323 1324 // We calculate the x positions of the characters in both lines.. 1325 sal_uInt16 nTopDiff = 0; 1326 sal_uInt16 nBotDiff = 0; 1327 if( nMaxWidth > Width() ) 1328 { 1329 nTopDiff = ( nMaxWidth - Width() ) / 2; 1330 Width( nMaxWidth ); 1331 } 1332 else 1333 nBotDiff = ( Width() - nMaxWidth ) / 2; 1334 switch( nTop) 1335 { 1336 case 3: aPos[1] = aPos[0] + nTopDiff; // no break 1337 case 2: aPos[nTop-1] = Width() - aPos[nTop-1]; 1338 } 1339 aPos[0] = 0; 1340 switch( nCount ) 1341 { 1342 case 5: aPos[4] = aPos[3] + nBotDiff; // no break 1343 case 3: aPos[nTop] = nBotDiff; break; 1344 case 6: aPos[4] = aPos[3] + nBotDiff; // no break 1345 case 4: aPos[nTop] = 0; // no break 1346 case 2: aPos[nCount-1] = Width() - aPos[nCount-1]; 1347 } 1348 1349 // Does the combined portion fit the line? 1350 const sal_Bool bFull = rInf.Width() < rInf.X() + Width(); 1351 if( bFull ) 1352 { 1353 if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp() 1354 || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) ) 1355 Width( (sal_uInt16)( rInf.Width() - rInf.X() ) ); 1356 else 1357 { 1358 Truncate(); 1359 Width( 0 ); 1360 SetLen( 0 ); 1361 if( rInf.GetLast() ) 1362 rInf.GetLast()->FormatEOL( rInf ); 1363 } 1364 } 1365 return bFull; 1366 } 1367 1368 /************************************************************************* 1369 * SwCombinedPortion::GetViewWidth(..) 1370 *************************************************************************/ 1371 1372 KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const 1373 { 1374 if( !GetLen() ) // for the dummy part at the end of the line, where 1375 return 0; // the combined portion doesn't fit. 1376 return SwFldPortion::GetViewWidth( rInf ); 1377 } 1378